routstrd 0.3.4 → 0.3.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/bun.lock +44 -2
- package/dist/daemon/index.js +62626 -19364
- package/dist/index.js +15 -6
- package/package.json +2 -2
- package/src/daemon/http/usage-summary.test.ts +27 -14
- package/src/tui/usage/render.ts +13 -6
- package/say_hi.sh +0 -32
package/dist/index.js
CHANGED
|
@@ -14293,13 +14293,22 @@ function renderToday(stats, width) {
|
|
|
14293
14293
|
const currentHour = new Date().getHours();
|
|
14294
14294
|
const _now = new Date;
|
|
14295
14295
|
const todayDateStr = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
|
14296
|
-
let todayStats
|
|
14297
|
-
|
|
14298
|
-
|
|
14296
|
+
let todayStats = {
|
|
14297
|
+
date: todayDateStr,
|
|
14298
|
+
requests: 0,
|
|
14299
|
+
satsCost: 0,
|
|
14300
|
+
promptTokens: 0,
|
|
14301
|
+
completionTokens: 0,
|
|
14302
|
+
totalTokens: 0
|
|
14303
|
+
};
|
|
14304
|
+
let recentDays = [];
|
|
14305
|
+
let hourlyMap = new Map;
|
|
14299
14306
|
if (stats.summary) {
|
|
14300
14307
|
const { days, hoursToday } = stats.summary;
|
|
14301
14308
|
const todayDayStat = days[0]?.date === todayDateStr ? days[0] : undefined;
|
|
14302
|
-
|
|
14309
|
+
if (todayDayStat) {
|
|
14310
|
+
todayStats = { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens };
|
|
14311
|
+
}
|
|
14303
14312
|
recentDays = days.filter((d) => d.date !== todayDateStr).slice(0, 6);
|
|
14304
14313
|
hourlyMap = new Map(hoursToday.map((h) => [h.hour, { requests: h.requests, satsCost: h.satsCost }]));
|
|
14305
14314
|
}
|
|
@@ -15587,7 +15596,7 @@ async function isCocodInstalled(cocodPath) {
|
|
|
15587
15596
|
// package.json
|
|
15588
15597
|
var package_default = {
|
|
15589
15598
|
name: "routstrd",
|
|
15590
|
-
version: "0.3.
|
|
15599
|
+
version: "0.3.5",
|
|
15591
15600
|
module: "src/index.ts",
|
|
15592
15601
|
type: "module",
|
|
15593
15602
|
private: false,
|
|
@@ -15611,7 +15620,7 @@ var package_default = {
|
|
|
15611
15620
|
},
|
|
15612
15621
|
dependencies: {
|
|
15613
15622
|
"@cashu/cashu-ts": "^4.3.0",
|
|
15614
|
-
"@routstr/sdk": "^0.3.
|
|
15623
|
+
"@routstr/sdk": "^0.3.14",
|
|
15615
15624
|
"applesauce-core": "^5.1.0",
|
|
15616
15625
|
"applesauce-relay": "^5.1.0",
|
|
15617
15626
|
"applesauce-wallet-connect": "^6.0.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "routstrd",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@cashu/cashu-ts": "^4.3.0",
|
|
27
|
-
"@routstr/sdk": "^0.3.
|
|
27
|
+
"@routstr/sdk": "^0.3.14",
|
|
28
28
|
"applesauce-core": "^5.1.0",
|
|
29
29
|
"applesauce-relay": "^5.1.0",
|
|
30
30
|
"applesauce-wallet-connect": "^6.0.0",
|
|
@@ -6,15 +6,27 @@ import { getUsageSummary, __resetUsageSummaryCacheForTest } from "./usage-summar
|
|
|
6
6
|
|
|
7
7
|
// ─── Test fixtures ────────────────────────────────────────────────────────────
|
|
8
8
|
//
|
|
9
|
-
// All timestamps
|
|
9
|
+
// All timestamps are computed relative to "now" so the fixtures never age
|
|
10
|
+
// out of getUsageSummary's 30-day rolling window. We anchor to a recent UTC
|
|
11
|
+
// midnight ~10 days ago and keep the same hour-of-day structure the
|
|
12
|
+
// tz-bucketing assertions depend on.
|
|
13
|
+
//
|
|
10
14
|
// tz = 300 (UTC-5 / EST). After shifting by -300min, UTC dates become:
|
|
11
|
-
// d1:
|
|
12
|
-
// d2:
|
|
13
|
-
// d3:
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
15
|
+
// d1: <anchor> 10:00Z → local <anchor> 05:00 → local day "<anchor>"
|
|
16
|
+
// d2: <anchor+1d> 03:00Z → local <anchor> 22:00 → local day "<anchor>"
|
|
17
|
+
// d3: <anchor+1d> 06:00Z → local <anchor+1d> 01:00 → local day "<anchor+1d>"
|
|
18
|
+
|
|
19
|
+
const _BASE_UTC_MIDNIGHT = Math.floor(Date.now() / 86_400_000) * 86_400_000;
|
|
20
|
+
const _ANCHOR_MS = _BASE_UTC_MIDNIGHT - 10 * 86_400_000; // 10 days ago UTC
|
|
21
|
+
const D1 = _ANCHOR_MS + 10 * 3_600_000; // 10:00Z → local day <anchor>
|
|
22
|
+
const D2 = _ANCHOR_MS + 1 * 86_400_000 + 3 * 3_600_000; // 03:00Z next day → local day <anchor>
|
|
23
|
+
const D3 = _ANCHOR_MS + 1 * 86_400_000 + 6 * 3_600_000; // 06:00Z next day → local day <anchor+1d>
|
|
24
|
+
|
|
25
|
+
/** Compute the local-day date string the same way the SDK's day grouping does. */
|
|
26
|
+
function localDayDateStr(ts: number, tzOffsetMinutes: number): string {
|
|
27
|
+
const d = new Date(ts - tzOffsetMinutes * 60_000);
|
|
28
|
+
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`;
|
|
29
|
+
}
|
|
18
30
|
|
|
19
31
|
const BASE_ENTRY: Omit<UsageTrackingEntry, "id" | "timestamp" | "modelId" | "client" | "totalTokens"> = {
|
|
20
32
|
baseUrl: "https://api.openai.com/",
|
|
@@ -152,23 +164,24 @@ describe("getUsageSummary", () => {
|
|
|
152
164
|
const summary = await getUsageSummary(driver, CLIENTS, TZ);
|
|
153
165
|
const { days } = summary;
|
|
154
166
|
|
|
155
|
-
// D1 (10:00Z)
|
|
156
|
-
//
|
|
167
|
+
// D1 (10:00Z) and D2 (next day 03:00Z) both bucket to local day <anchor>;
|
|
168
|
+
// D3 (next day 06:00Z) buckets to local day <anchor+1d>.
|
|
169
|
+
// So: day <anchor> has e1+e2, day <anchor+1d> has e3+e4
|
|
157
170
|
expect(days.length).toBeGreaterThanOrEqual(2);
|
|
158
171
|
|
|
159
|
-
// Most-recent-first:
|
|
160
|
-
expect(days[0]!.date).toBe(
|
|
172
|
+
// Most-recent-first: <anchor+1d> first
|
|
173
|
+
expect(days[0]!.date).toBe(localDayDateStr(D3, TZ));
|
|
161
174
|
expect(days[0]!.requests).toBe(2); // e3, e4
|
|
162
175
|
expect(days[0]!.satsCost).toBe(8 + 50);
|
|
163
176
|
|
|
164
|
-
expect(days[1]!.date).toBe(
|
|
177
|
+
expect(days[1]!.date).toBe(localDayDateStr(D1, TZ));
|
|
165
178
|
expect(days[1]!.requests).toBe(2); // e1, e2
|
|
166
179
|
expect(days[1]!.satsCost).toBe(10 + 20);
|
|
167
180
|
});
|
|
168
181
|
|
|
169
182
|
it("returns empty hoursToday (test entries are not today)", async () => {
|
|
170
183
|
const summary = await getUsageSummary(driver, CLIENTS, TZ);
|
|
171
|
-
// Test entries are
|
|
184
|
+
// Test entries are ~10 days ago, not today
|
|
172
185
|
expect(summary.hoursToday).toHaveLength(0);
|
|
173
186
|
});
|
|
174
187
|
|
package/src/tui/usage/render.ts
CHANGED
|
@@ -278,18 +278,25 @@ export function renderToday(stats: UsageStats, width: number): string {
|
|
|
278
278
|
const _now = new Date();
|
|
279
279
|
const todayDateStr = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
|
280
280
|
|
|
281
|
-
let todayStats: { date: string; requests: number; satsCost: number; promptTokens: number; completionTokens: number; totalTokens: number }
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
let todayStats: { date: string; requests: number; satsCost: number; promptTokens: number; completionTokens: number; totalTokens: number } = {
|
|
282
|
+
date: todayDateStr,
|
|
283
|
+
requests: 0,
|
|
284
|
+
satsCost: 0,
|
|
285
|
+
promptTokens: 0,
|
|
286
|
+
completionTokens: 0,
|
|
287
|
+
totalTokens: 0,
|
|
288
|
+
};
|
|
289
|
+
let recentDays: Array<{ date: string; requests: number; satsCost: number; totalTokens: number; promptTokens: number; completionTokens: number }> = [];
|
|
290
|
+
let hourlyMap: Map<number, { requests: number; satsCost: number }> = new Map();
|
|
284
291
|
|
|
285
292
|
if (stats.summary) {
|
|
286
293
|
// Use server-aggregated data
|
|
287
294
|
const { days, hoursToday } = stats.summary;
|
|
288
295
|
// days[0] is most-recent-first; check if it's today
|
|
289
296
|
const todayDayStat = days[0]?.date === todayDateStr ? days[0] : undefined;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
297
|
+
if (todayDayStat) {
|
|
298
|
+
todayStats = { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens };
|
|
299
|
+
}
|
|
293
300
|
// Exclude today by date (it has its own box) rather than by position —
|
|
294
301
|
// days[0] is only today when there was activity today.
|
|
295
302
|
recentDays = days.filter((d) => d.date !== todayDateStr).slice(0, 6);
|
package/say_hi.sh
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
LANGUAGES=(
|
|
5
|
-
"Mandarin Chinese"
|
|
6
|
-
"Spanish"
|
|
7
|
-
"English"
|
|
8
|
-
"Hindi"
|
|
9
|
-
"Arabic"
|
|
10
|
-
"Portuguese"
|
|
11
|
-
"Bengali"
|
|
12
|
-
"Russian"
|
|
13
|
-
"Japanese"
|
|
14
|
-
"German"
|
|
15
|
-
"French"
|
|
16
|
-
"Italian"
|
|
17
|
-
"Korean"
|
|
18
|
-
"Turkish"
|
|
19
|
-
"Vietnamese"
|
|
20
|
-
"Tamil"
|
|
21
|
-
"Polish"
|
|
22
|
-
"Dutch"
|
|
23
|
-
"Swahili"
|
|
24
|
-
"Thai"
|
|
25
|
-
"Greek"
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
for lang in "${LANGUAGES[@]}"; do
|
|
29
|
-
echo "=== $lang ==="
|
|
30
|
-
pi -p -c "in $lang"
|
|
31
|
-
echo
|
|
32
|
-
done
|