@inferhub/usage 0.1.2 → 0.1.4
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/bin/statusline.mjs +5 -7
- package/dist/format.d.ts +3 -3
- package/dist/format.js +46 -24
- package/package.json +1 -1
- package/src/format.ts +61 -37
package/bin/statusline.mjs
CHANGED
|
@@ -22,15 +22,13 @@ try {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
undefined;
|
|
30
|
-
|
|
25
|
+
// Do NOT pass Claude's session_id through: InferHub derives its own conversation
|
|
26
|
+
// key server-side (hash of system+first user message / X-Session-Id). Claude's
|
|
27
|
+
// UUID almost never matches, which produced "sess 0r/0". Default API path uses
|
|
28
|
+
// the user's latest InferHub session.
|
|
31
29
|
const { usage } = await client.fetchAccountUsageAuto({
|
|
32
30
|
window: "day",
|
|
33
|
-
|
|
31
|
+
force: false,
|
|
34
32
|
});
|
|
35
33
|
const contextPct =
|
|
36
34
|
typeof session?.context_window?.used_percentage === "number"
|
package/dist/format.d.ts
CHANGED
|
@@ -5,14 +5,14 @@ export declare function shortModel(model: string | null | undefined): string;
|
|
|
5
5
|
/**
|
|
6
6
|
* Compact one-liner for Claude statusline / Codex Stop summary.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Plain-language labels. Free models correctly show $0 billed while still
|
|
9
|
+
* reporting request/token activity.
|
|
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
|
|
15
|
+
/** When true, include Claude local list-price estimate. Default false. */
|
|
16
16
|
showEstimate?: boolean;
|
|
17
17
|
}): string;
|
|
18
18
|
/** Multi-line human report for /usage skills. */
|
package/dist/format.js
CHANGED
|
@@ -20,38 +20,60 @@ export function shortModel(model) {
|
|
|
20
20
|
const parts = model.split("/");
|
|
21
21
|
return parts[parts.length - 1] || model;
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
/** Human activity + optional billed spend. */
|
|
24
|
+
function activity(label, opts) {
|
|
25
|
+
const req = Number(opts.requests ?? 0);
|
|
26
|
+
const tok = Number(opts.totalTokens ?? 0);
|
|
27
|
+
const spend = Number(opts.spendUsdc ?? 0);
|
|
28
|
+
const bits = [];
|
|
29
|
+
if (req > 0 || tok > 0) {
|
|
30
|
+
bits.push(`${req.toLocaleString()} req`);
|
|
31
|
+
bits.push(`${tokens(tok)} tok`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
bits.push("no traffic");
|
|
35
|
+
}
|
|
25
36
|
if (spend > 0)
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
bits.push(money(spend));
|
|
38
|
+
else
|
|
39
|
+
bits.push("$0");
|
|
40
|
+
return `${label} ${bits.join(" / ")}`;
|
|
28
41
|
}
|
|
29
42
|
/**
|
|
30
43
|
* Compact one-liner for Claude statusline / Codex Stop summary.
|
|
31
44
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
45
|
+
* Plain-language labels. Free models correctly show $0 billed while still
|
|
46
|
+
* reporting request/token activity.
|
|
34
47
|
*/
|
|
35
48
|
export function formatStatusLine(usage, extras) {
|
|
36
|
-
const
|
|
37
|
-
? spendOrActivity(usage.session.spend_usdc, usage.session.requests, usage.session.total_tokens)
|
|
38
|
-
: null;
|
|
39
|
-
const day = spendOrActivity(usage.window.spend_usdc, usage.window.requests, usage.window.total_tokens);
|
|
40
|
-
const all = money(usage.all_time.spend_usdc);
|
|
49
|
+
const model = extras?.model ? shortModel(extras.model) : null;
|
|
41
50
|
const bal = money(usage.balance.amount_usdc);
|
|
42
51
|
const top = shortModel(usage.top_model?.model);
|
|
43
|
-
const model = extras?.model ? shortModel(extras.model) : null;
|
|
44
52
|
const ctx = extras?.contextPct != null && Number.isFinite(extras.contextPct)
|
|
45
|
-
? `${Math.round(extras.contextPct)}%
|
|
53
|
+
? `${Math.round(extras.contextPct)}% context`
|
|
46
54
|
: null;
|
|
47
55
|
const parts = ["InferHub"];
|
|
48
56
|
if (model)
|
|
49
57
|
parts.push(model);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
// Latest conversation on InferHub (server-derived session), if present and useful
|
|
59
|
+
if (usage.session && (usage.session.requests > 0 || Number(usage.session.spend_usdc) > 0)) {
|
|
60
|
+
parts.push(activity("session", {
|
|
61
|
+
spendUsdc: usage.session.spend_usdc,
|
|
62
|
+
requests: usage.session.requests,
|
|
63
|
+
totalTokens: usage.session.total_tokens,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
parts.push(activity("today", {
|
|
67
|
+
spendUsdc: usage.window.spend_usdc,
|
|
68
|
+
requests: usage.window.requests,
|
|
69
|
+
totalTokens: usage.window.total_tokens,
|
|
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}`);
|
|
55
77
|
if (top && top !== "—")
|
|
56
78
|
parts.push(`top ${top}`);
|
|
57
79
|
if (ctx)
|
|
@@ -60,21 +82,21 @@ export function formatStatusLine(usage, extras) {
|
|
|
60
82
|
extras.sessionCostUsd != null &&
|
|
61
83
|
Number.isFinite(extras.sessionCostUsd) &&
|
|
62
84
|
extras.sessionCostUsd > 0) {
|
|
63
|
-
parts.push(`est ${money(extras.sessionCostUsd)}`);
|
|
85
|
+
parts.push(`claude-est ${money(extras.sessionCostUsd)}`);
|
|
64
86
|
}
|
|
65
87
|
return parts.join(" · ");
|
|
66
88
|
}
|
|
67
89
|
/** Multi-line human report for /usage skills. */
|
|
68
90
|
export function formatReport(usage) {
|
|
69
91
|
const lines = [
|
|
70
|
-
"InferHub usage",
|
|
71
|
-
` Balance:
|
|
92
|
+
"InferHub usage (billed USDC)",
|
|
93
|
+
` Balance: ${money(usage.balance.amount_usdc)} remaining`,
|
|
72
94
|
];
|
|
73
95
|
if (usage.session) {
|
|
74
|
-
lines.push(` Session:
|
|
96
|
+
lines.push(` Session: ${usage.session.requests} requests · ${tokens(usage.session.total_tokens)} tokens · ${money(usage.session.spend_usdc)} billed`);
|
|
75
97
|
}
|
|
76
|
-
lines.push(` ${usage.window.
|
|
98
|
+
lines.push(` Today: ${usage.window.requests} requests · ${tokens(usage.window.total_tokens)} tokens · ${money(usage.window.spend_usdc)} billed`, ` All-time: ${usage.all_time.requests} requests · ${tokens(usage.all_time.total_tokens)} tokens · ${money(usage.all_time.spend_usdc)} billed`, ` Top model: ${usage.top_model?.model ?? "—"} (${usage.top_model?.requests ?? 0} req · ${money(usage.top_model?.spend_usdc ?? 0)})`);
|
|
77
99
|
if (usage.cache?.cached)
|
|
78
|
-
lines.push(` (cached
|
|
100
|
+
lines.push(` (cached ${usage.cache.ttl_seconds}s)`);
|
|
79
101
|
return lines.join("\n");
|
|
80
102
|
}
|
package/package.json
CHANGED
package/src/format.ts
CHANGED
|
@@ -20,21 +20,35 @@ export function shortModel(model: string | null | undefined): string {
|
|
|
20
20
|
return parts[parts.length - 1] || model;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/** Human activity + optional billed spend. */
|
|
24
|
+
function activity(
|
|
25
|
+
label: string,
|
|
26
|
+
opts: {
|
|
27
|
+
spendUsdc?: string | number | null;
|
|
28
|
+
requests?: number | null;
|
|
29
|
+
totalTokens?: number | null;
|
|
30
|
+
},
|
|
27
31
|
): string {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
const req = Number(opts.requests ?? 0);
|
|
33
|
+
const tok = Number(opts.totalTokens ?? 0);
|
|
34
|
+
const spend = Number(opts.spendUsdc ?? 0);
|
|
35
|
+
const bits: string[] = [];
|
|
36
|
+
if (req > 0 || tok > 0) {
|
|
37
|
+
bits.push(`${req.toLocaleString()} req`);
|
|
38
|
+
bits.push(`${tokens(tok)} tok`);
|
|
39
|
+
} else {
|
|
40
|
+
bits.push("no traffic");
|
|
41
|
+
}
|
|
42
|
+
if (spend > 0) bits.push(money(spend));
|
|
43
|
+
else bits.push("$0");
|
|
44
|
+
return `${label} ${bits.join(" / ")}`;
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
/**
|
|
34
48
|
* Compact one-liner for Claude statusline / Codex Stop summary.
|
|
35
49
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
50
|
+
* Plain-language labels. Free models correctly show $0 billed while still
|
|
51
|
+
* reporting request/token activity.
|
|
38
52
|
*/
|
|
39
53
|
export function formatStatusLine(
|
|
40
54
|
usage: AccountUsage,
|
|
@@ -42,37 +56,47 @@ export function formatStatusLine(
|
|
|
42
56
|
sessionCostUsd?: number | null;
|
|
43
57
|
contextPct?: number | null;
|
|
44
58
|
model?: string | null;
|
|
45
|
-
/** When true, include Claude
|
|
59
|
+
/** When true, include Claude local list-price estimate. Default false. */
|
|
46
60
|
showEstimate?: boolean;
|
|
47
61
|
},
|
|
48
62
|
): string {
|
|
49
|
-
const
|
|
50
|
-
? spendOrActivity(
|
|
51
|
-
usage.session.spend_usdc,
|
|
52
|
-
usage.session.requests,
|
|
53
|
-
usage.session.total_tokens,
|
|
54
|
-
)
|
|
55
|
-
: null;
|
|
56
|
-
const day = spendOrActivity(
|
|
57
|
-
usage.window.spend_usdc,
|
|
58
|
-
usage.window.requests,
|
|
59
|
-
usage.window.total_tokens,
|
|
60
|
-
);
|
|
61
|
-
const all = money(usage.all_time.spend_usdc);
|
|
63
|
+
const model = extras?.model ? shortModel(extras.model) : null;
|
|
62
64
|
const bal = money(usage.balance.amount_usdc);
|
|
63
65
|
const top = shortModel(usage.top_model?.model);
|
|
64
|
-
const model = extras?.model ? shortModel(extras.model) : null;
|
|
65
66
|
const ctx =
|
|
66
67
|
extras?.contextPct != null && Number.isFinite(extras.contextPct)
|
|
67
|
-
? `${Math.round(extras.contextPct)}%
|
|
68
|
+
? `${Math.round(extras.contextPct)}% context`
|
|
68
69
|
: null;
|
|
69
70
|
|
|
70
71
|
const parts: string[] = ["InferHub"];
|
|
71
72
|
if (model) parts.push(model);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
|
|
74
|
+
// Latest conversation on InferHub (server-derived session), if present and useful
|
|
75
|
+
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
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
parts.push(
|
|
86
|
+
activity("today", {
|
|
87
|
+
spendUsdc: usage.window.spend_usdc,
|
|
88
|
+
requests: usage.window.requests,
|
|
89
|
+
totalTokens: usage.window.total_tokens,
|
|
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}`);
|
|
76
100
|
if (top && top !== "—") parts.push(`top ${top}`);
|
|
77
101
|
if (ctx) parts.push(ctx);
|
|
78
102
|
|
|
@@ -82,7 +106,7 @@ export function formatStatusLine(
|
|
|
82
106
|
Number.isFinite(extras.sessionCostUsd) &&
|
|
83
107
|
extras.sessionCostUsd > 0
|
|
84
108
|
) {
|
|
85
|
-
parts.push(`est ${money(extras.sessionCostUsd)}`);
|
|
109
|
+
parts.push(`claude-est ${money(extras.sessionCostUsd)}`);
|
|
86
110
|
}
|
|
87
111
|
|
|
88
112
|
return parts.join(" · ");
|
|
@@ -91,19 +115,19 @@ export function formatStatusLine(
|
|
|
91
115
|
/** Multi-line human report for /usage skills. */
|
|
92
116
|
export function formatReport(usage: AccountUsage): string {
|
|
93
117
|
const lines = [
|
|
94
|
-
"InferHub usage",
|
|
95
|
-
` Balance:
|
|
118
|
+
"InferHub usage (billed USDC)",
|
|
119
|
+
` Balance: ${money(usage.balance.amount_usdc)} remaining`,
|
|
96
120
|
];
|
|
97
121
|
if (usage.session) {
|
|
98
122
|
lines.push(
|
|
99
|
-
` Session:
|
|
123
|
+
` Session: ${usage.session.requests} requests · ${tokens(usage.session.total_tokens)} tokens · ${money(usage.session.spend_usdc)} billed`,
|
|
100
124
|
);
|
|
101
125
|
}
|
|
102
126
|
lines.push(
|
|
103
|
-
` ${usage.window.
|
|
104
|
-
` All-time:
|
|
105
|
-
` Top model:
|
|
127
|
+
` Today: ${usage.window.requests} requests · ${tokens(usage.window.total_tokens)} tokens · ${money(usage.window.spend_usdc)} billed`,
|
|
128
|
+
` All-time: ${usage.all_time.requests} requests · ${tokens(usage.all_time.total_tokens)} tokens · ${money(usage.all_time.spend_usdc)} billed`,
|
|
129
|
+
` Top model: ${usage.top_model?.model ?? "—"} (${usage.top_model?.requests ?? 0} req · ${money(usage.top_model?.spend_usdc ?? 0)})`,
|
|
106
130
|
);
|
|
107
|
-
if (usage.cache?.cached) lines.push(` (cached
|
|
131
|
+
if (usage.cache?.cached) lines.push(` (cached ${usage.cache.ttl_seconds}s)`);
|
|
108
132
|
return lines.join("\n");
|
|
109
133
|
}
|