@juliantanx/aiusage 1.0.2 → 1.0.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/dist/{chunk-C6IKRE2P.js → chunk-2DX56FB6.js} +79 -15
- package/dist/{dist-XHYTXDVT.js → dist-4I33E46P.js} +1 -1
- package/dist/index.js +284 -58
- package/dist/web/_app/immutable/assets/0.DDbFsqNI.css +1 -0
- package/dist/web/_app/immutable/assets/2.fho1OPpm.css +1 -0
- package/dist/web/_app/immutable/assets/8.9sovMx-u.css +1 -0
- package/dist/web/_app/immutable/assets/9.Doxq00gF.css +1 -0
- package/dist/web/_app/immutable/assets/_layout.RgD-pTKj.css +1 -0
- package/dist/web/_app/immutable/assets/_page.9sovMx-u.css +1 -0
- package/dist/web/_app/immutable/assets/_page.DTuZozBR.css +1 -0
- package/dist/web/_app/immutable/assets/_page.Doxq00gF.css +1 -0
- package/dist/web/_app/immutable/chunks/ToolSelector.DIzQsA4_.js +2 -0
- package/dist/web/_app/immutable/chunks/api.D-M_rVlI.js +1 -0
- package/dist/web/_app/immutable/chunks/entry.-i5eOrF8.js +3 -0
- package/dist/web/_app/immutable/chunks/{index.Dm-3G3np.js → index.BjVwNvJa.js} +1 -1
- package/dist/web/_app/immutable/chunks/{index.CzqoKkoo.js → index.CUfK07C5.js} +1 -1
- package/dist/web/_app/immutable/chunks/scheduler.DukoKnjQ.js +1 -0
- package/dist/web/_app/immutable/chunks/{stores.BSVKBbO8.js → stores.BJHWQcKv.js} +1 -1
- package/dist/web/_app/immutable/entry/app.Pb7AfjR8.js +2 -0
- package/dist/web/_app/immutable/entry/start.DyuR4tFJ.js +1 -0
- package/dist/web/_app/immutable/nodes/0.BhkxfbMC.js +1 -0
- package/dist/web/_app/immutable/nodes/{1.xdMqApFe.js → 1.CNO4bJXv.js} +1 -1
- package/dist/web/_app/immutable/nodes/{8.BSeUhVCa.js → 10.1LgqVOtM.js} +1 -1
- package/dist/web/_app/immutable/nodes/{9.DJXBgSiY.js → 11.BOfGogcw.js} +1 -1
- package/dist/web/_app/immutable/nodes/2.C_8jrQsV.js +3 -0
- package/dist/web/_app/immutable/nodes/{3.Bqg88zQg.js → 3.Lz_pbSpS.js} +1 -1
- package/dist/web/_app/immutable/nodes/{4.B3zrG0ip.js → 4.BCB36ta_.js} +1 -1
- package/dist/web/_app/immutable/nodes/{2.CJyBxUXd.js → 5.CykeLKzi.js} +1 -1
- package/dist/web/_app/immutable/nodes/{5.C3h9wXyF.js → 6.De73932o.js} +1 -1
- package/dist/web/_app/immutable/nodes/{6.C8xhym7b.js → 7.6OEKXCWR.js} +1 -1
- package/dist/web/_app/immutable/nodes/8.niqPZkB9.js +1 -0
- package/dist/web/_app/immutable/nodes/9.DRZSbXAV.js +1 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +9 -9
- package/package.json +4 -2
- package/dist/web/_app/immutable/assets/0.BTUc0PXb.css +0 -1
- package/dist/web/_app/immutable/assets/7.8R_5Laqi.css +0 -1
- package/dist/web/_app/immutable/assets/_layout.DLyrrG29.css +0 -1
- package/dist/web/_app/immutable/assets/_page.8R_5Laqi.css +0 -1
- package/dist/web/_app/immutable/chunks/ToolSelector.kb97TteP.js +0 -2
- package/dist/web/_app/immutable/chunks/api.DyoIo4nG.js +0 -1
- package/dist/web/_app/immutable/chunks/entry.DbT6jbyV.js +0 -3
- package/dist/web/_app/immutable/chunks/scheduler.Dx1bs0RQ.js +0 -1
- package/dist/web/_app/immutable/entry/app.BjD-8RWO.js +0 -2
- package/dist/web/_app/immutable/entry/start.Dg2jUJRH.js +0 -1
- package/dist/web/_app/immutable/nodes/0.DiQJRuoG.js +0 -1
- package/dist/web/_app/immutable/nodes/7.C950CTxa.js +0 -1
- /package/dist/web/_app/immutable/assets/{8.BcbNCOTS.css → 10.BcbNCOTS.css} +0 -0
- /package/dist/web/_app/immutable/assets/{9.QhlpTtkf.css → 11.QhlpTtkf.css} +0 -0
- /package/dist/web/_app/immutable/assets/{2.I4bgY8QS.css → 5.I4bgY8QS.css} +0 -0
- /package/dist/web/_app/immutable/assets/{5.BeDwa7mS.css → 6.BeDwa7mS.css} +0 -0
- /package/dist/web/_app/immutable/assets/{6.BYQidWiw.css → 7.BYQidWiw.css} +0 -0
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
removePriceOverride,
|
|
14
14
|
resolvePrice,
|
|
15
15
|
setPriceOverride
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2DX56FB6.js";
|
|
17
17
|
|
|
18
18
|
// src/cli.ts
|
|
19
19
|
import { Command } from "commander";
|
|
@@ -156,7 +156,7 @@ function looksMachineGenerated(name) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// src/api/server.ts
|
|
159
|
-
function getDateRangeFilter(range, from, to, prefix = "") {
|
|
159
|
+
function getDateRangeFilter(range, from, to, prefix = "", weekStart = 1) {
|
|
160
160
|
const ts = prefix ? `${prefix}.ts` : "ts";
|
|
161
161
|
if (from && to) {
|
|
162
162
|
const startMs = new Date(from).getTime();
|
|
@@ -167,8 +167,9 @@ function getDateRangeFilter(range, from, to, prefix = "") {
|
|
|
167
167
|
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
168
168
|
if (range === "week") {
|
|
169
169
|
const dayOfWeek = today.getDay();
|
|
170
|
+
const diff = (dayOfWeek - weekStart + 7) % 7;
|
|
170
171
|
const startOfWeek = new Date(today);
|
|
171
|
-
startOfWeek.setDate(today.getDate() -
|
|
172
|
+
startOfWeek.setDate(today.getDate() - diff);
|
|
172
173
|
return { where: `AND ${ts} >= @start`, params: { start: startOfWeek.getTime() } };
|
|
173
174
|
}
|
|
174
175
|
if (range === "month") {
|
|
@@ -218,6 +219,8 @@ function getDeviceFilter(device, currentDeviceInstanceId) {
|
|
|
218
219
|
};
|
|
219
220
|
}
|
|
220
221
|
function createApiServer(db, options) {
|
|
222
|
+
const cfg = loadConfig();
|
|
223
|
+
let weekStart = cfg?.weekStart ?? 1;
|
|
221
224
|
const server = http.createServer(async (req, res) => {
|
|
222
225
|
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
223
226
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -245,7 +248,7 @@ function createApiServer(db, options) {
|
|
|
245
248
|
}
|
|
246
249
|
const device = url.searchParams.get("device");
|
|
247
250
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
248
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
251
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
249
252
|
const tool = url.searchParams.get("tool");
|
|
250
253
|
const tf = getToolFilter(tool);
|
|
251
254
|
let totals;
|
|
@@ -333,7 +336,7 @@ function createApiServer(db, options) {
|
|
|
333
336
|
for (const row of byToolRows) {
|
|
334
337
|
byTool[row.tool] = { tokens: row.tokens, cost: row.cost };
|
|
335
338
|
}
|
|
336
|
-
const drJoin = getDateRangeFilter(range, from, to, "r");
|
|
339
|
+
const drJoin = getDateRangeFilter(range, from, to, "r", weekStart);
|
|
337
340
|
const dfJoin = df.where ? df.where.replace(/device_instance_id/g, "r.device_instance_id") : "";
|
|
338
341
|
const tfJoin = getToolFilter(tool, "r");
|
|
339
342
|
const topToolCalls = db.prepare(`
|
|
@@ -359,7 +362,7 @@ function createApiServer(db, options) {
|
|
|
359
362
|
return;
|
|
360
363
|
}
|
|
361
364
|
if (url.pathname === "/api/tokens") {
|
|
362
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
365
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
363
366
|
const device = url.searchParams.get("device");
|
|
364
367
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
365
368
|
const tool = url.searchParams.get("tool");
|
|
@@ -409,7 +412,7 @@ function createApiServer(db, options) {
|
|
|
409
412
|
return;
|
|
410
413
|
}
|
|
411
414
|
if (url.pathname === "/api/cost") {
|
|
412
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
415
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
413
416
|
const device = url.searchParams.get("device");
|
|
414
417
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
415
418
|
const tool = url.searchParams.get("tool");
|
|
@@ -485,7 +488,7 @@ function createApiServer(db, options) {
|
|
|
485
488
|
return;
|
|
486
489
|
}
|
|
487
490
|
if (url.pathname === "/api/models") {
|
|
488
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
491
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
489
492
|
const device = url.searchParams.get("device");
|
|
490
493
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
491
494
|
const tool = url.searchParams.get("tool");
|
|
@@ -546,7 +549,7 @@ function createApiServer(db, options) {
|
|
|
546
549
|
json(res, { toolCalls: [] });
|
|
547
550
|
return;
|
|
548
551
|
}
|
|
549
|
-
const dr = getDateRangeFilter(range, from, to, "r");
|
|
552
|
+
const dr = getDateRangeFilter(range, from, to, "r", weekStart);
|
|
550
553
|
const tool = url.searchParams.get("tool");
|
|
551
554
|
const tf = getToolFilter(tool, "r");
|
|
552
555
|
const totalRow = db.prepare(`
|
|
@@ -573,7 +576,7 @@ function createApiServer(db, options) {
|
|
|
573
576
|
if (url.pathname === "/api/sessions") {
|
|
574
577
|
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1", 10));
|
|
575
578
|
const pageSize = Math.min(100, Math.max(1, parseInt(url.searchParams.get("pageSize") || "50", 10)));
|
|
576
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
579
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
577
580
|
const device = url.searchParams.get("device");
|
|
578
581
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
579
582
|
const tool = url.searchParams.get("tool");
|
|
@@ -617,7 +620,7 @@ function createApiServer(db, options) {
|
|
|
617
620
|
return;
|
|
618
621
|
}
|
|
619
622
|
if (url.pathname === "/api/projects") {
|
|
620
|
-
const dr = getDateRangeFilter(range, from, to);
|
|
623
|
+
const dr = getDateRangeFilter(range, from, to, "", weekStart);
|
|
621
624
|
const device = url.searchParams.get("device");
|
|
622
625
|
const df = getDeviceFilter(device, options?.currentDeviceInstanceId);
|
|
623
626
|
const tool = url.searchParams.get("tool");
|
|
@@ -710,9 +713,9 @@ function createApiServer(db, options) {
|
|
|
710
713
|
thinking: data.thinking
|
|
711
714
|
};
|
|
712
715
|
setPriceOverride(data.model, entry);
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
saveConfig(
|
|
716
|
+
const cfg2 = loadConfig() ?? {};
|
|
717
|
+
cfg2.priceOverrides = { ...cfg2.priceOverrides, [data.model]: entry };
|
|
718
|
+
saveConfig(cfg2);
|
|
716
719
|
json(res, { ok: true });
|
|
717
720
|
} catch {
|
|
718
721
|
json(res, { error: { code: "INVALID_JSON", message: "Invalid JSON body" } }, 400);
|
|
@@ -726,17 +729,17 @@ function createApiServer(db, options) {
|
|
|
726
729
|
return;
|
|
727
730
|
}
|
|
728
731
|
removePriceOverride(model);
|
|
729
|
-
const
|
|
730
|
-
if (
|
|
731
|
-
delete
|
|
732
|
-
saveConfig(
|
|
732
|
+
const cfg2 = loadConfig() ?? {};
|
|
733
|
+
if (cfg2.priceOverrides) {
|
|
734
|
+
delete cfg2.priceOverrides[model];
|
|
735
|
+
saveConfig(cfg2);
|
|
733
736
|
}
|
|
734
737
|
json(res, { ok: true });
|
|
735
738
|
return;
|
|
736
739
|
}
|
|
737
740
|
}
|
|
738
741
|
if (url.pathname === "/api/pricing/recalc" && req.method === "POST") {
|
|
739
|
-
const { resolvePrice: resolvePrice2 } = await import("./dist-
|
|
742
|
+
const { resolvePrice: resolvePrice2 } = await import("./dist-4I33E46P.js");
|
|
740
743
|
const BATCH_SIZE2 = 1e3;
|
|
741
744
|
let updated = 0;
|
|
742
745
|
let lastId = "";
|
|
@@ -844,6 +847,121 @@ function createApiServer(db, options) {
|
|
|
844
847
|
json(res, { currentDeviceInstanceId: currentId, devices });
|
|
845
848
|
return;
|
|
846
849
|
}
|
|
850
|
+
if (url.pathname === "/api/config/credential" && req.method === "GET") {
|
|
851
|
+
const ref = url.searchParams.get("ref")?.trim();
|
|
852
|
+
if (!ref) {
|
|
853
|
+
json(res, { error: { code: "MISSING_CREDENTIAL_REF", message: "credential ref is required" } }, 400);
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const value = loadCredential(ref);
|
|
857
|
+
if (!value) {
|
|
858
|
+
json(res, { error: { code: "CREDENTIAL_NOT_FOUND", message: "Credential not found" } }, 404);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
json(res, { value });
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (url.pathname === "/api/config") {
|
|
865
|
+
if (req.method === "GET") {
|
|
866
|
+
const currentCfg = loadConfig() ?? {};
|
|
867
|
+
const { credentials, priceOverrides, platform: platform4, ...rest } = currentCfg;
|
|
868
|
+
json(res, {
|
|
869
|
+
device: rest.device ?? null,
|
|
870
|
+
weekStart: rest.weekStart ?? 1,
|
|
871
|
+
dashboardPollInterval: rest.dashboardPollInterval ?? null,
|
|
872
|
+
parseInterval: rest.parseInterval ?? null,
|
|
873
|
+
retentionDays: rest.retentionDays ?? null,
|
|
874
|
+
sources: {
|
|
875
|
+
"claude-code": rest.sources?.["claude-code"] ?? null,
|
|
876
|
+
codex: rest.sources?.codex ?? null,
|
|
877
|
+
openclaw: rest.sources?.openclaw ?? null,
|
|
878
|
+
opencode: rest.sources?.opencode ?? null
|
|
879
|
+
},
|
|
880
|
+
sync: rest.sync ?? null,
|
|
881
|
+
credentialKeys: credentials ? Object.keys(credentials) : []
|
|
882
|
+
});
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (req.method === "PUT") {
|
|
886
|
+
let body = "";
|
|
887
|
+
for await (const chunk of req) body += chunk;
|
|
888
|
+
try {
|
|
889
|
+
const update = JSON.parse(body);
|
|
890
|
+
const existing = loadConfig() ?? {};
|
|
891
|
+
if ("device" in update) {
|
|
892
|
+
if (!update.device) delete existing.device;
|
|
893
|
+
else existing.device = String(update.device);
|
|
894
|
+
}
|
|
895
|
+
if ("weekStart" in update) {
|
|
896
|
+
const ws = Number(update.weekStart);
|
|
897
|
+
if (ws === 0 || ws === 1) {
|
|
898
|
+
existing.weekStart = ws;
|
|
899
|
+
weekStart = ws;
|
|
900
|
+
} else {
|
|
901
|
+
delete existing.weekStart;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
if ("dashboardPollInterval" in update) {
|
|
905
|
+
if (!update.dashboardPollInterval) delete existing.dashboardPollInterval;
|
|
906
|
+
else existing.dashboardPollInterval = Number(update.dashboardPollInterval);
|
|
907
|
+
}
|
|
908
|
+
if ("parseInterval" in update) {
|
|
909
|
+
if (!update.parseInterval) delete existing.parseInterval;
|
|
910
|
+
else existing.parseInterval = Number(update.parseInterval);
|
|
911
|
+
}
|
|
912
|
+
if ("retentionDays" in update) {
|
|
913
|
+
if (!update.retentionDays) delete existing.retentionDays;
|
|
914
|
+
else existing.retentionDays = Number(update.retentionDays);
|
|
915
|
+
}
|
|
916
|
+
if (update.sources && typeof update.sources === "object") {
|
|
917
|
+
const src = update.sources;
|
|
918
|
+
const s = existing.sources ?? {};
|
|
919
|
+
for (const key of ["claude-code", "codex", "openclaw", "opencode"]) {
|
|
920
|
+
if (key in src) {
|
|
921
|
+
if (!src[key]) delete s[key];
|
|
922
|
+
else s[key] = String(src[key]);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (Object.keys(s).length) existing.sources = s;
|
|
926
|
+
else delete existing.sources;
|
|
927
|
+
}
|
|
928
|
+
if ("sync" in update) {
|
|
929
|
+
const syncUpdate = update.sync;
|
|
930
|
+
if (!syncUpdate?.backend) {
|
|
931
|
+
delete existing.sync;
|
|
932
|
+
} else {
|
|
933
|
+
const backendVal = String(syncUpdate.backend);
|
|
934
|
+
if (backendVal !== "github" && backendVal !== "s3") {
|
|
935
|
+
json(res, { error: { code: "INVALID_BACKEND", message: "sync.backend must be github or s3" } }, 400);
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
const newSync = { backend: backendVal };
|
|
939
|
+
for (const f of ["repo", "bucket", "prefix", "endpoint", "region", "credentialRef"]) {
|
|
940
|
+
if (syncUpdate[f]) newSync[f] = String(syncUpdate[f]);
|
|
941
|
+
}
|
|
942
|
+
existing.sync = newSync;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (update.credentials && typeof update.credentials === "object") {
|
|
946
|
+
const creds = update.credentials;
|
|
947
|
+
const c = existing.credentials ?? {};
|
|
948
|
+
for (const [key, val] of Object.entries(creds)) {
|
|
949
|
+
if (val !== "" && val !== null && val !== void 0) {
|
|
950
|
+
c[key] = String(val);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
if (Object.keys(c).length) existing.credentials = c;
|
|
954
|
+
else delete existing.credentials;
|
|
955
|
+
}
|
|
956
|
+
saveConfig(existing);
|
|
957
|
+
options?.onConfigUpdated?.();
|
|
958
|
+
json(res, { ok: true });
|
|
959
|
+
} catch {
|
|
960
|
+
json(res, { error: { code: "INVALID_JSON", message: "Invalid JSON body" } }, 400);
|
|
961
|
+
}
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
847
965
|
json(res, { error: { code: "NOT_FOUND", message: "Endpoint not found" } }, 404);
|
|
848
966
|
} catch (error) {
|
|
849
967
|
console.error("API error:", error);
|
|
@@ -1272,8 +1390,10 @@ async function runParse(db, filterTool, options) {
|
|
|
1272
1390
|
});
|
|
1273
1391
|
const result = aggregator.parseLine(line, context);
|
|
1274
1392
|
if (result) {
|
|
1275
|
-
|
|
1276
|
-
|
|
1393
|
+
if (result.record) {
|
|
1394
|
+
insertRecord(db, result.record);
|
|
1395
|
+
parsedCount++;
|
|
1396
|
+
}
|
|
1277
1397
|
for (const tc of result.toolCalls) {
|
|
1278
1398
|
insertToolCall(db, tc);
|
|
1279
1399
|
toolCallCount++;
|
|
@@ -1665,35 +1785,56 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
1665
1785
|
token;
|
|
1666
1786
|
cacheDir;
|
|
1667
1787
|
dataDir;
|
|
1788
|
+
branch;
|
|
1668
1789
|
constructor(config) {
|
|
1669
1790
|
this.repo = config.repo;
|
|
1670
1791
|
this.token = config.token;
|
|
1671
1792
|
this.cacheDir = config.cacheDir;
|
|
1672
1793
|
this.dataDir = join4(config.cacheDir, "data");
|
|
1794
|
+
this.branch = config.branch ?? "main";
|
|
1673
1795
|
}
|
|
1674
1796
|
get remoteUrl() {
|
|
1675
1797
|
return `https://x-access-token:${this.token}@github.com/${this.repo}.git`;
|
|
1676
1798
|
}
|
|
1799
|
+
sanitizeError(error) {
|
|
1800
|
+
if (error instanceof Error) {
|
|
1801
|
+
const pattern = /https:\/\/[^@\s]+@github\.com/g;
|
|
1802
|
+
error.message = error.message.replace(pattern, "https://github.com");
|
|
1803
|
+
const err = error;
|
|
1804
|
+
if (typeof err.stderr === "string") {
|
|
1805
|
+
err.stderr = err.stderr.replace(pattern, "https://github.com");
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return error;
|
|
1809
|
+
}
|
|
1677
1810
|
async git(args, cwd) {
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1811
|
+
try {
|
|
1812
|
+
const { stdout } = await exec("git", args, {
|
|
1813
|
+
cwd: cwd ?? this.cacheDir,
|
|
1814
|
+
timeout: 6e4,
|
|
1815
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
1816
|
+
});
|
|
1817
|
+
return stdout.trim();
|
|
1818
|
+
} catch (error) {
|
|
1819
|
+
throw this.sanitizeError(error);
|
|
1820
|
+
}
|
|
1684
1821
|
}
|
|
1685
1822
|
/** Clone or pull the repo to get latest remote state */
|
|
1686
1823
|
async prepare() {
|
|
1687
1824
|
try {
|
|
1688
1825
|
await stat(join4(this.cacheDir, ".git"));
|
|
1689
|
-
await this.git(["fetch", "origin",
|
|
1690
|
-
await this.git(["reset", "--hard",
|
|
1826
|
+
await this.git(["fetch", "origin", this.branch, "--depth=1"]);
|
|
1827
|
+
await this.git(["reset", "--hard", `origin/${this.branch}`]);
|
|
1691
1828
|
} catch {
|
|
1692
1829
|
await mkdir(this.cacheDir, { recursive: true });
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1830
|
+
try {
|
|
1831
|
+
await exec("git", ["clone", "--depth=1", this.remoteUrl, this.cacheDir], {
|
|
1832
|
+
timeout: 12e4,
|
|
1833
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
1834
|
+
});
|
|
1835
|
+
} catch (error) {
|
|
1836
|
+
throw this.sanitizeError(error);
|
|
1837
|
+
}
|
|
1697
1838
|
}
|
|
1698
1839
|
}
|
|
1699
1840
|
async readFile(path2) {
|
|
@@ -1725,11 +1866,11 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
1725
1866
|
await this.git(["commit", "-m", `sync ${(/* @__PURE__ */ new Date()).toISOString()}`]);
|
|
1726
1867
|
for (let attempt = 1; attempt <= _GitSyncBackend.MAX_PUSH_RETRIES; attempt++) {
|
|
1727
1868
|
try {
|
|
1728
|
-
await this.git(["push", "origin",
|
|
1869
|
+
await this.git(["push", "origin", this.branch]);
|
|
1729
1870
|
return true;
|
|
1730
1871
|
} catch (error) {
|
|
1731
1872
|
if (attempt >= _GitSyncBackend.MAX_PUSH_RETRIES) throw error;
|
|
1732
|
-
await this.git(["pull", "--rebase", "origin",
|
|
1873
|
+
await this.git(["pull", "--rebase", "origin", this.branch]);
|
|
1733
1874
|
}
|
|
1734
1875
|
}
|
|
1735
1876
|
return false;
|
|
@@ -1803,14 +1944,14 @@ var S3SyncBackend = class {
|
|
|
1803
1944
|
do {
|
|
1804
1945
|
const command = new ListObjectsV2Command({
|
|
1805
1946
|
Bucket: this.bucket,
|
|
1806
|
-
Prefix:
|
|
1947
|
+
Prefix: this.prefix,
|
|
1807
1948
|
ContinuationToken: continuationToken
|
|
1808
1949
|
});
|
|
1809
1950
|
const response = await this.client.send(command);
|
|
1810
1951
|
if (response.Contents) {
|
|
1811
1952
|
for (const obj of response.Contents) {
|
|
1812
1953
|
const key = obj.Key;
|
|
1813
|
-
const relPath = key.slice(
|
|
1954
|
+
const relPath = key.slice(this.prefix.length);
|
|
1814
1955
|
if (relPath.endsWith(".ndjson")) {
|
|
1815
1956
|
files.push(relPath);
|
|
1816
1957
|
}
|
|
@@ -1916,6 +2057,22 @@ async function runSync(db, options) {
|
|
|
1916
2057
|
return result;
|
|
1917
2058
|
}
|
|
1918
2059
|
|
|
2060
|
+
// src/commands/clean.ts
|
|
2061
|
+
function cleanOldData(db, days) {
|
|
2062
|
+
const cutoff = Date.now() - days * 864e5;
|
|
2063
|
+
const recordsResult = db.prepare("DELETE FROM records WHERE ts < ?").run(cutoff);
|
|
2064
|
+
const deletedCount = recordsResult.changes;
|
|
2065
|
+
const syncedResult = db.prepare("DELETE FROM synced_records WHERE ts < ?").run(cutoff);
|
|
2066
|
+
const deletedSyncedCount = syncedResult.changes;
|
|
2067
|
+
const orphanResult = db.prepare("DELETE FROM tool_calls WHERE record_id IS NULL AND ts < ?").run(cutoff);
|
|
2068
|
+
const deletedOrphanToolCalls = orphanResult.changes;
|
|
2069
|
+
return {
|
|
2070
|
+
deletedCount,
|
|
2071
|
+
deletedSyncedCount,
|
|
2072
|
+
deletedOrphanToolCalls
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
|
|
1919
2076
|
// src/sync/runtime.ts
|
|
1920
2077
|
var SyncRuntimeController = class {
|
|
1921
2078
|
runSyncFn;
|
|
@@ -1981,6 +2138,77 @@ var SyncRuntimeController = class {
|
|
|
1981
2138
|
}
|
|
1982
2139
|
};
|
|
1983
2140
|
|
|
2141
|
+
// src/runtime/settings-controller.ts
|
|
2142
|
+
var DEFAULT_CLEANUP_INTERVAL_MS = 60 * 60 * 1e3;
|
|
2143
|
+
var RuntimeSettingsController = class {
|
|
2144
|
+
db;
|
|
2145
|
+
loadConfigFn;
|
|
2146
|
+
runParseFn;
|
|
2147
|
+
runCleanupFn;
|
|
2148
|
+
cleanupIntervalMs;
|
|
2149
|
+
parseTimer = null;
|
|
2150
|
+
cleanupTimer = null;
|
|
2151
|
+
parseInFlight = false;
|
|
2152
|
+
started = false;
|
|
2153
|
+
constructor(options) {
|
|
2154
|
+
this.db = options.db;
|
|
2155
|
+
this.loadConfigFn = options.loadConfig;
|
|
2156
|
+
this.runParseFn = options.runParse;
|
|
2157
|
+
this.runCleanupFn = options.runCleanup;
|
|
2158
|
+
this.cleanupIntervalMs = options.cleanupIntervalMs ?? DEFAULT_CLEANUP_INTERVAL_MS;
|
|
2159
|
+
}
|
|
2160
|
+
start() {
|
|
2161
|
+
if (this.started) return;
|
|
2162
|
+
this.started = true;
|
|
2163
|
+
this.applyConfig();
|
|
2164
|
+
}
|
|
2165
|
+
reload() {
|
|
2166
|
+
if (!this.started) return;
|
|
2167
|
+
this.applyConfig();
|
|
2168
|
+
}
|
|
2169
|
+
stop() {
|
|
2170
|
+
this.started = false;
|
|
2171
|
+
if (this.parseTimer) clearInterval(this.parseTimer);
|
|
2172
|
+
if (this.cleanupTimer) clearInterval(this.cleanupTimer);
|
|
2173
|
+
this.parseTimer = null;
|
|
2174
|
+
this.cleanupTimer = null;
|
|
2175
|
+
}
|
|
2176
|
+
applyConfig() {
|
|
2177
|
+
if (this.parseTimer) clearInterval(this.parseTimer);
|
|
2178
|
+
if (this.cleanupTimer) clearInterval(this.cleanupTimer);
|
|
2179
|
+
this.parseTimer = null;
|
|
2180
|
+
this.cleanupTimer = null;
|
|
2181
|
+
const config = this.loadConfigFn();
|
|
2182
|
+
const parseInterval = Number(config?.parseInterval ?? 0);
|
|
2183
|
+
const retentionDays = Number(config?.retentionDays ?? 0);
|
|
2184
|
+
if (parseInterval > 0) {
|
|
2185
|
+
this.parseTimer = setInterval(() => {
|
|
2186
|
+
void this.runParseSafely();
|
|
2187
|
+
}, parseInterval);
|
|
2188
|
+
}
|
|
2189
|
+
if (retentionDays > 0) {
|
|
2190
|
+
this.cleanupTimer = setInterval(() => {
|
|
2191
|
+
try {
|
|
2192
|
+
this.runCleanupFn(this.db, retentionDays);
|
|
2193
|
+
} catch (err) {
|
|
2194
|
+
console.error("[settings-controller] cleanup failed:", err);
|
|
2195
|
+
}
|
|
2196
|
+
}, this.cleanupIntervalMs);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
async runParseSafely() {
|
|
2200
|
+
if (this.parseInFlight) return;
|
|
2201
|
+
this.parseInFlight = true;
|
|
2202
|
+
try {
|
|
2203
|
+
await this.runParseFn(this.db);
|
|
2204
|
+
} catch (err) {
|
|
2205
|
+
console.error("[settings-controller] parse failed:", err);
|
|
2206
|
+
} finally {
|
|
2207
|
+
this.parseInFlight = false;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2211
|
+
|
|
1984
2212
|
// src/commands/serve.ts
|
|
1985
2213
|
var MIME_TYPES = {
|
|
1986
2214
|
".html": "text/html",
|
|
@@ -2005,13 +2233,25 @@ function serve(options) {
|
|
|
2005
2233
|
runSync: (runtimeOptions) => runSync(options.db, runtimeOptions).then(() => void 0),
|
|
2006
2234
|
getPersistedState: () => getState(AIUSAGE_DIR)
|
|
2007
2235
|
});
|
|
2236
|
+
const runtimeSettings = new RuntimeSettingsController({
|
|
2237
|
+
db: options.db,
|
|
2238
|
+
loadConfig,
|
|
2239
|
+
runParse,
|
|
2240
|
+
runCleanup: cleanOldData
|
|
2241
|
+
});
|
|
2242
|
+
runtimeSettings.start();
|
|
2008
2243
|
const apiServer = createApiServer(options.db, {
|
|
2009
2244
|
currentDeviceInstanceId: getState(AIUSAGE_DIR)?.deviceInstanceId,
|
|
2010
2245
|
onRefresh: () => runParse(options.db),
|
|
2011
2246
|
onSyncStart: () => syncRuntime.start(),
|
|
2012
|
-
getSyncStatus: () => syncRuntime.getStatus()
|
|
2247
|
+
getSyncStatus: () => syncRuntime.getStatus(),
|
|
2248
|
+
onConfigUpdated: () => runtimeSettings.reload()
|
|
2013
2249
|
});
|
|
2014
|
-
const webBuildDir =
|
|
2250
|
+
const webBuildDir = (() => {
|
|
2251
|
+
const prodDir = join6(dirname(fileURLToPath(import.meta.url)), "web");
|
|
2252
|
+
if (existsSync5(prodDir)) return prodDir;
|
|
2253
|
+
return join6(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "web", "build");
|
|
2254
|
+
})();
|
|
2015
2255
|
const server = http2.createServer(async (req, res) => {
|
|
2016
2256
|
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
2017
2257
|
if (url.pathname.startsWith("/api/")) {
|
|
@@ -2047,11 +2287,13 @@ function serve(options) {
|
|
|
2047
2287
|
});
|
|
2048
2288
|
process.on("SIGINT", () => {
|
|
2049
2289
|
console.log("\nShutting down...");
|
|
2290
|
+
runtimeSettings.stop();
|
|
2050
2291
|
server.close(() => {
|
|
2051
2292
|
process.exit(0);
|
|
2052
2293
|
});
|
|
2053
2294
|
});
|
|
2054
2295
|
process.on("SIGTERM", () => {
|
|
2296
|
+
runtimeSettings.stop();
|
|
2055
2297
|
server.close(() => {
|
|
2056
2298
|
process.exit(0);
|
|
2057
2299
|
});
|
|
@@ -2085,7 +2327,7 @@ function runInit(options) {
|
|
|
2085
2327
|
sync: {
|
|
2086
2328
|
backend: "github",
|
|
2087
2329
|
repo: options.repo,
|
|
2088
|
-
credentialRef: `
|
|
2330
|
+
credentialRef: `github/${options.repo}/token`
|
|
2089
2331
|
},
|
|
2090
2332
|
device: options.device ?? existingConfig?.device,
|
|
2091
2333
|
platform: existingConfig?.platform ?? platform3(),
|
|
@@ -2131,7 +2373,7 @@ Consent recorded for schema v1.`
|
|
|
2131
2373
|
prefix,
|
|
2132
2374
|
endpoint: options.endpoint,
|
|
2133
2375
|
region: options.region ?? "auto",
|
|
2134
|
-
credentialRef: `
|
|
2376
|
+
credentialRef: `s3/${options.bucket}/accessKeyId`
|
|
2135
2377
|
},
|
|
2136
2378
|
device: options.device ?? existingConfig?.device,
|
|
2137
2379
|
platform: existingConfig?.platform ?? platform3(),
|
|
@@ -2352,22 +2594,6 @@ function exportData(db, format) {
|
|
|
2352
2594
|
return lines.join("\n");
|
|
2353
2595
|
}
|
|
2354
2596
|
|
|
2355
|
-
// src/commands/clean.ts
|
|
2356
|
-
function cleanOldData(db, days) {
|
|
2357
|
-
const cutoff = Date.now() - days * 864e5;
|
|
2358
|
-
const recordsResult = db.prepare("DELETE FROM records WHERE ts < ?").run(cutoff);
|
|
2359
|
-
const deletedCount = recordsResult.changes;
|
|
2360
|
-
const syncedResult = db.prepare("DELETE FROM synced_records WHERE ts < ?").run(cutoff);
|
|
2361
|
-
const deletedSyncedCount = syncedResult.changes;
|
|
2362
|
-
const orphanResult = db.prepare("DELETE FROM tool_calls WHERE record_id IS NULL AND ts < ?").run(cutoff);
|
|
2363
|
-
const deletedOrphanToolCalls = orphanResult.changes;
|
|
2364
|
-
return {
|
|
2365
|
-
deletedCount,
|
|
2366
|
-
deletedSyncedCount,
|
|
2367
|
-
deletedOrphanToolCalls
|
|
2368
|
-
};
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
2597
|
// src/commands/recalc.ts
|
|
2372
2598
|
var BATCH_SIZE = 1e3;
|
|
2373
2599
|
function recalcPricing(db) {
|
|
@@ -2643,7 +2869,7 @@ function createDatabase(path2) {
|
|
|
2643
2869
|
import { join as join8 } from "path";
|
|
2644
2870
|
var DB_PATH = join8(AIUSAGE_DIR, "cache.db");
|
|
2645
2871
|
var program = new Command();
|
|
2646
|
-
program.name("aiusage").version("1.0.
|
|
2872
|
+
program.name("aiusage").version(true ? "1.0.4" : "dev").description("CLI tool for AI usage statistics");
|
|
2647
2873
|
program.action(() => {
|
|
2648
2874
|
const db = createDatabase(DB_PATH);
|
|
2649
2875
|
const state = getState(AIUSAGE_DIR);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{margin:0;padding:0;box-sizing:border-box}body{font-family:DM Sans,sans-serif;background:var(--bg-base);color:var(--text-primary);min-height:100vh;-webkit-font-smoothing:antialiased;transition:background .3s ease,color .3s ease}:root,:root[data-theme=dark]{--bg-base:#0b0e14;--bg-surface:#111620;--bg-raised:#171c28;--bg-hover:#1c2333;--border-subtle:rgba(255, 255, 255, .06);--border-medium:rgba(255, 255, 255, .1);--text-primary:#e6edf3;--text-secondary:#8b949e;--text-muted:#484f58;--accent:#f0b429;--accent-dim:rgba(240, 180, 41, .15);--accent-glow:rgba(240, 180, 41, .3);--green:#2ea66a;--green-dim:rgba(46, 166, 106, .15);--blue:#3b82f6;--blue-dim:rgba(59, 130, 246, .15);--purple:#a78bfa;--purple-dim:rgba(167, 139, 250, .15);--rose:#f43f5e;--rose-dim:rgba(244, 63, 94, .15);--mono:"JetBrains Mono", monospace;--grain-opacity:.03}:root[data-theme=light]{--bg-base:#f4f5f7;--bg-surface:#ffffff;--bg-raised:#f0f1f3;--bg-hover:#e8eaed;--border-subtle:rgba(0, 0, 0, .07);--border-medium:rgba(0, 0, 0, .12);--text-primary:#1a1d23;--text-secondary:#57606a;--text-muted:#8b949e;--accent:#c78c06;--accent-dim:rgba(199, 140, 6, .1);--accent-glow:rgba(199, 140, 6, .15);--green:#1a7f4b;--green-dim:rgba(26, 127, 75, .1);--blue:#2563eb;--blue-dim:rgba(37, 99, 235, .1);--purple:#7c3aed;--purple-dim:rgba(124, 58, 237, .1);--rose:#dc2626;--rose-dim:rgba(220, 38, 38, .1);--mono:"JetBrains Mono", monospace;--grain-opacity:.015}.grain.svelte-zqr7pm.svelte-zqr7pm{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:9999;opacity:var(--grain-opacity);background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");background-repeat:repeat;background-size:128px}.app.svelte-zqr7pm.svelte-zqr7pm{display:flex;flex-direction:column;min-height:100vh}header.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:2rem;padding:0 2rem;height:56px;background:var(--bg-surface);border-bottom:1px solid var(--border-subtle);position:sticky;top:0;z-index:100;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);transition:background .3s ease,border-color .3s ease}.brand.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.5rem;flex-shrink:0;text-decoration:none}.logo.svelte-zqr7pm.svelte-zqr7pm{font-size:1.25rem;color:var(--accent);filter:drop-shadow(0 0 6px var(--accent-glow));transition:color .3s ease}.name.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-weight:700;font-size:.95rem;letter-spacing:-.02em;color:var(--text-primary);transition:color .3s ease}nav.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.25rem;flex:1}nav.svelte-zqr7pm a.svelte-zqr7pm{text-decoration:none;color:var(--text-secondary);padding:.4rem .75rem;border-radius:6px;font-size:.8rem;font-weight:500;line-height:1;transition:all .15s ease;white-space:nowrap}nav.svelte-zqr7pm a.svelte-zqr7pm:hover{color:var(--text-primary);background:var(--bg-hover)}nav.svelte-zqr7pm a.active.svelte-zqr7pm{color:var(--accent);background:var(--accent-dim)}.controls.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.35rem;padding:.35rem .6rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-size:.75rem;font-weight:500;cursor:pointer;transition:all .15s ease}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm:disabled{opacity:.6;cursor:not-allowed}.sync-icon.svelte-zqr7pm.svelte-zqr7pm{font-size:.85rem;line-height:1}.sync-toggle.svelte-zqr7pm:disabled .sync-icon.svelte-zqr7pm{animation:svelte-zqr7pm-spin 1s linear infinite}@keyframes svelte-zqr7pm-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.sync-label.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-size:.7rem;font-weight:600;letter-spacing:.02em}.sync-label.ok.svelte-zqr7pm.svelte-zqr7pm{color:var(--green)}.sync-label.err.svelte-zqr7pm.svelte-zqr7pm{color:var(--rose)}.theme-toggle.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.4rem;padding:.35rem .65rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-size:.75rem;font-weight:500;cursor:pointer;transition:all .15s ease}.theme-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}.theme-icon.svelte-zqr7pm.svelte-zqr7pm{font-size:.85rem;line-height:1}.theme-label.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-size:.7rem;font-weight:600;letter-spacing:.02em}.lang-toggle.svelte-zqr7pm.svelte-zqr7pm{padding:.35rem .75rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-family:var(--mono);font-size:.75rem;font-weight:600;cursor:pointer;transition:all .15s ease;letter-spacing:.02em}.lang-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}main.svelte-zqr7pm.svelte-zqr7pm{flex:1;padding:2rem;max-width:1200px;width:100%;margin:0 auto;animation:svelte-zqr7pm-fadeUp .4s ease}@keyframes svelte-zqr7pm-fadeUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.card{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:10px;padding:1.25rem;transition:border-color .2s ease,background .3s ease}.card:hover{border-color:var(--border-medium)}.section-title{font-family:var(--mono);font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:.75rem}table{width:100%;border-collapse:collapse}th{font-family:var(--mono);font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);text-align:left;padding:.6rem .75rem;border-bottom:1px solid var(--border-subtle)}td{padding:.6rem .75rem;border-bottom:1px solid var(--border-subtle);font-size:.85rem;color:var(--text-secondary);transition:color .3s ease}tbody tr{transition:background .15s ease}tbody tr:hover{background:var(--bg-hover)}.mono{font-family:var(--mono)}.accent{color:var(--accent)}.green{color:var(--green)}.blue{color:var(--blue)}.purple{color:var(--purple)}.state-msg{text-align:center;padding:4rem 2rem;color:var(--text-muted);font-size:.9rem}.state-msg h2{font-family:var(--mono);font-size:1rem;font-weight:600;color:var(--text-secondary);margin-bottom:.5rem}.state-msg.error{color:var(--rose)}button{font-family:DM Sans,sans-serif}@media (max-width: 768px){header.svelte-zqr7pm.svelte-zqr7pm{flex-wrap:wrap;height:auto;padding:.75rem 1rem;gap:.5rem}nav.svelte-zqr7pm.svelte-zqr7pm{order:3;width:100%;overflow-x:auto;padding-bottom:.25rem}.controls.svelte-zqr7pm.svelte-zqr7pm{margin-left:auto}main.svelte-zqr7pm.svelte-zqr7pm{padding:1rem}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.top-bar.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;padding:.55rem .9rem;background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:8px}.live-wrap.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:center;gap:.45rem;padding:.2rem .55rem;border:1px solid rgba(46,166,106,.3);border-radius:4px;background:#2ea66a12;flex-shrink:0}.live-dot.svelte-1i8v7x1.svelte-1i8v7x1{width:6px;height:6px;border-radius:50%;background:var(--green);animation:svelte-1i8v7x1-livePulse 2.4s ease-in-out infinite}.live-wrap.pulse.svelte-1i8v7x1 .live-dot.svelte-1i8v7x1{animation:svelte-1i8v7x1-liveBurst .5s ease}.live-label.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.58rem;font-weight:700;letter-spacing:.2em;color:var(--green)}@keyframes svelte-1i8v7x1-livePulse{0%,to{box-shadow:0 0 #2ea66a80}50%{box-shadow:0 0 0 4px #2ea66a00}}@keyframes svelte-1i8v7x1-liveBurst{0%{transform:scale(1)}40%{transform:scale(1.7);box-shadow:0 0 8px var(--green)}to{transform:scale(1)}}.range-badge.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.62rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--accent);border:1px solid var(--accent-dim);border-radius:4px;padding:.2rem .55rem;background:var(--accent-dim)}.clock-block.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;flex-direction:column;align-items:flex-start;margin-left:auto;gap:.05rem}.clock-time.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.88rem;font-weight:700;letter-spacing:.05em;color:var(--text-primary);font-variant-numeric:tabular-nums}.clock-date.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.54rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted)}.cfg-btn.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-muted);cursor:pointer;transition:border-color .15s,color .15s;flex-shrink:0}.cfg-btn.svelte-1i8v7x1.svelte-1i8v7x1:hover{border-color:var(--accent);color:var(--accent)}.cfg-icon.svelte-1i8v7x1.svelte-1i8v7x1{font-size:.85rem;line-height:1}.counter-section.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;display:flex;flex-direction:column;align-items:center;padding:3rem 2rem 1.75rem;margin-bottom:1rem;background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:14px;overflow:hidden;transition:border-color .4s}.counter-section.pulsing.svelte-1i8v7x1.svelte-1i8v7x1{border-color:#f0b42938}.counter-section.svelte-1i8v7x1.svelte-1i8v7x1:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--accent) 50%,transparent);opacity:.65}.grid-bg.svelte-1i8v7x1.svelte-1i8v7x1{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;background-image:radial-gradient(circle,rgba(240,180,41,.12) 1px,transparent 1px);background-size:28px 28px;opacity:.45}.counter-glow.svelte-1i8v7x1.svelte-1i8v7x1{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:560px;height:260px;background:radial-gradient(ellipse,rgba(240,180,41,.07) 0%,transparent 65%);pointer-events:none}.scan-line.svelte-1i8v7x1.svelte-1i8v7x1{position:absolute;top:0;bottom:0;left:-50%;width:35%;background:linear-gradient(90deg,transparent,rgba(240,180,41,.04),transparent);animation:svelte-1i8v7x1-scanPass 6s linear infinite;pointer-events:none}@keyframes svelte-1i8v7x1-scanPass{0%{left:-40%}to{left:140%}}.counter-eyebrow.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;z-index:1;display:flex;align-items:center;gap:1rem;margin-bottom:1.1rem}.eyebrow-line.svelte-1i8v7x1.svelte-1i8v7x1{display:block;height:1px;width:60px;background:linear-gradient(90deg,transparent,var(--border-medium))}.eyebrow-line.svelte-1i8v7x1.svelte-1i8v7x1:last-child{transform:scaleX(-1)}.eyebrow-text.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.6rem;font-weight:700;letter-spacing:.22em;text-transform:uppercase;color:var(--text-muted)}.counter-number.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;z-index:1;font-family:var(--mono);font-size:clamp(2.8rem,6.5vw,5.5rem);font-weight:800;letter-spacing:-.035em;line-height:1;color:var(--accent);text-shadow:0 0 30px rgba(240,180,41,.38),0 0 90px rgba(240,180,41,.13);font-variant-numeric:tabular-nums;transition:opacity .3s,text-shadow .5s}.counter-number.refreshing.svelte-1i8v7x1.svelte-1i8v7x1{opacity:.5}.counter-section.pulsing.svelte-1i8v7x1 .counter-number.svelte-1i8v7x1{text-shadow:0 0 50px rgba(240,180,41,.55),0 0 130px rgba(240,180,41,.22)}.counter-sub.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;z-index:1;display:flex;align-items:center;gap:1.75rem;margin-top:1.4rem}.sub-chip.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;flex-direction:column;align-items:center;gap:.15rem}.sub-arrow.svelte-1i8v7x1.svelte-1i8v7x1{font-size:.65rem;color:var(--text-muted);line-height:1}.sub-lbl.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.5rem;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--text-muted)}.sub-val.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.82rem;font-weight:600;color:var(--text-secondary);font-variant-numeric:tabular-nums}.sub-sep.svelte-1i8v7x1.svelte-1i8v7x1{width:1px;height:28px;background:var(--border-subtle);margin-top:.3rem}.refresh-bar-track.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;z-index:1;width:100%;height:2px;background:var(--border-subtle);border-radius:1px;margin-top:2rem;overflow:hidden}.refresh-bar-fill.svelte-1i8v7x1.svelte-1i8v7x1{height:100%;background:linear-gradient(90deg,var(--accent-dim),var(--accent));border-radius:1px;transition:width 1s linear;box-shadow:0 0 6px var(--accent-glow)}.refresh-meta.svelte-1i8v7x1.svelte-1i8v7x1{position:relative;z-index:1;display:flex;align-items:center;gap:.75rem;margin-top:.5rem;font-family:var(--mono);font-size:.56rem;font-weight:600;letter-spacing:.08em;color:var(--text-muted)}.refreshing-label.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--accent)}.now-btn.svelte-1i8v7x1.svelte-1i8v7x1{margin-left:auto;padding:.15rem .5rem;border:1px solid var(--border-medium);border-radius:4px;background:transparent;font-family:var(--mono);font-size:.55rem;font-weight:600;letter-spacing:.06em;color:var(--text-muted);cursor:pointer;transition:border-color .15s,color .15s}.now-btn.svelte-1i8v7x1.svelte-1i8v7x1:hover{border-color:var(--accent);color:var(--accent)}.stats-strip.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:stretch;background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:10px;margin-bottom:1rem;overflow:hidden}.stat-block.svelte-1i8v7x1.svelte-1i8v7x1{flex:1;display:flex;align-items:center;gap:.9rem;padding:1.1rem 1.4rem;position:relative;transition:background .15s}.stat-block.svelte-1i8v7x1.svelte-1i8v7x1:before{content:"";position:absolute;top:0;left:0;right:0;height:1px}.stat-block.svelte-1i8v7x1.svelte-1i8v7x1:hover{background:var(--bg-raised)}.stat-cost.svelte-1i8v7x1.svelte-1i8v7x1:before{background:var(--green)}.stat-sess.svelte-1i8v7x1.svelte-1i8v7x1:before{background:var(--blue)}.stat-days.svelte-1i8v7x1.svelte-1i8v7x1:before{background:var(--purple)}.strip-divider.svelte-1i8v7x1.svelte-1i8v7x1{width:1px;background:var(--border-subtle);margin:.75rem 0}.stat-icon-wrap.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:1.4rem;line-height:1;opacity:.22;flex-shrink:0}.stat-cost.svelte-1i8v7x1 .stat-icon-wrap.svelte-1i8v7x1{color:var(--green)}.stat-sess.svelte-1i8v7x1 .stat-icon-wrap.svelte-1i8v7x1{color:var(--blue)}.stat-days.svelte-1i8v7x1 .stat-icon-wrap.svelte-1i8v7x1{color:var(--purple)}.stat-info.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;flex-direction:column;gap:.22rem}.stat-lbl.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.56rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--text-muted)}.stat-val.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:1.75rem;font-weight:700;letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}.cost-val.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--green);text-shadow:0 0 18px rgba(46,166,106,.25)}.sess-val.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--blue);text-shadow:0 0 18px rgba(59,130,246,.25)}.days-val.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--purple);text-shadow:0 0 18px rgba(167,139,250,.25)}.comp-wrap.svelte-1i8v7x1.svelte-1i8v7x1{margin-bottom:.5rem}.comp-bar.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;height:26px;border-radius:6px;overflow:hidden;border:1px solid var(--border-subtle);background:var(--bg-raised)}.seg.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:center;justify-content:center;overflow:hidden;min-width:0;transition:width 1.5s cubic-bezier(.25,.46,.45,.94)}.seg-lbl.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.5rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;padding:0 4px}.seg-input.svelte-1i8v7x1.svelte-1i8v7x1{background:#f0b42933;border-right:1px solid var(--bg-base)}.seg-output.svelte-1i8v7x1.svelte-1i8v7x1{background:#3b82f62e;border-right:1px solid var(--bg-base)}.seg-cr.svelte-1i8v7x1.svelte-1i8v7x1{background:#a78bfa2b;border-right:1px solid var(--bg-base)}.seg-cw.svelte-1i8v7x1.svelte-1i8v7x1{background:#2ea66a2b}.seg-input.svelte-1i8v7x1 .seg-lbl.svelte-1i8v7x1{color:var(--accent)}.seg-output.svelte-1i8v7x1 .seg-lbl.svelte-1i8v7x1{color:var(--blue)}.seg-cr.svelte-1i8v7x1 .seg-lbl.svelte-1i8v7x1{color:var(--purple)}.seg-cw.svelte-1i8v7x1 .seg-lbl.svelte-1i8v7x1{color:var(--green)}.comp-legend.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;gap:1.25rem;margin-top:.45rem;padding:0 .2rem;flex-wrap:wrap}.leg.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.54rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase}.leg-i.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--accent)}.leg-o.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--blue)}.leg-cr.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--purple)}.leg-cw.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--green)}.overlay-backdrop.svelte-1i8v7x1.svelte-1i8v7x1{position:fixed;top:0;right:0;bottom:0;left:0;z-index:200;background:#070a1099;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);animation:svelte-1i8v7x1-fadeIn .15s ease}@keyframes svelte-1i8v7x1-fadeIn{0%{opacity:0}to{opacity:1}}.config-panel.svelte-1i8v7x1.svelte-1i8v7x1{position:fixed;z-index:201;top:50%;left:50%;transform:translate(-50%,-50%);width:min(400px,90vw);background:var(--bg-surface);border:1px solid var(--border-medium);border-radius:12px;padding:1.5rem;animation:svelte-1i8v7x1-panelIn .2s cubic-bezier(.34,1.56,.64,1);box-shadow:0 24px 80px #00000080}@keyframes svelte-1i8v7x1-panelIn{0%{opacity:0;transform:translate(-50%,-46%)}to{opacity:1;transform:translate(-50%,-50%)}}.cfg-header.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.25rem}.cfg-title.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.65rem;font-weight:700;letter-spacing:.2em;color:var(--text-muted)}.cfg-close.svelte-1i8v7x1.svelte-1i8v7x1{width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border-medium);border-radius:4px;background:transparent;color:var(--text-muted);font-size:.7rem;cursor:pointer;transition:border-color .15s,color .15s}.cfg-close.svelte-1i8v7x1.svelte-1i8v7x1:hover{border-color:var(--rose);color:var(--rose)}.cfg-section.svelte-1i8v7x1.svelte-1i8v7x1{margin-bottom:1.1rem}.cfg-label.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.58rem;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--text-muted);margin-bottom:.5rem}.cfg-pills.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;gap:.4rem;flex-wrap:wrap}.pill.svelte-1i8v7x1.svelte-1i8v7x1{padding:.3rem .75rem;border:1px solid var(--border-medium);border-radius:5px;background:var(--bg-raised);font-family:var(--mono);font-size:.7rem;font-weight:600;color:var(--text-secondary);cursor:pointer;transition:border-color .15s,color .15s,background .15s;white-space:nowrap}.pill.svelte-1i8v7x1.svelte-1i8v7x1:hover{border-color:var(--accent);color:var(--accent)}.pill.active.svelte-1i8v7x1.svelte-1i8v7x1{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}.pill-eg.svelte-1i8v7x1.svelte-1i8v7x1{opacity:.5;font-size:.6rem;margin-left:.3rem}.cfg-refresh-info.svelte-1i8v7x1.svelte-1i8v7x1{margin-top:.75rem;padding:.6rem .75rem;border:1px solid var(--border-subtle);border-radius:6px;background:var(--bg-raised)}.refresh-info-text.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.6rem;font-weight:600;letter-spacing:.04em;color:var(--text-muted)}.settings-link.svelte-1i8v7x1.svelte-1i8v7x1{color:var(--accent);text-decoration:none}.settings-link.svelte-1i8v7x1.svelte-1i8v7x1:hover{text-decoration:underline}.splash-loading.svelte-1i8v7x1.svelte-1i8v7x1,.splash-error.svelte-1i8v7x1.svelte-1i8v7x1,.splash-empty.svelte-1i8v7x1.svelte-1i8v7x1{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;min-height:320px;text-align:center}.splash-spinner.svelte-1i8v7x1.svelte-1i8v7x1{width:32px;height:32px;border:2px solid var(--border-subtle);border-top-color:var(--accent);border-radius:50%;animation:svelte-1i8v7x1-spin .8s linear infinite}@keyframes svelte-1i8v7x1-spin{to{transform:rotate(360deg)}}.splash-text.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.65rem;font-weight:700;letter-spacing:.25em;color:var(--text-muted);animation:svelte-1i8v7x1-blink 1.2s ease infinite}@keyframes svelte-1i8v7x1-blink{0%,to{opacity:1}50%{opacity:.35}}.err-code.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:2rem;font-weight:800;color:var(--rose)}.err-msg.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.8rem;color:var(--text-muted)}.retry-btn.svelte-1i8v7x1.svelte-1i8v7x1{margin-top:.5rem;padding:.4rem 1.2rem;border:1px solid var(--rose);border-radius:6px;background:transparent;font-family:var(--mono);font-size:.7rem;font-weight:700;color:var(--rose);cursor:pointer;transition:background .15s}.retry-btn.svelte-1i8v7x1.svelte-1i8v7x1:hover{background:#f43f5e1a}.empty-icon.svelte-1i8v7x1.svelte-1i8v7x1{font-size:2.5rem;color:var(--text-muted)}.empty-title.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.9rem;font-weight:700;letter-spacing:.2em;color:var(--text-secondary)}.empty-hint.svelte-1i8v7x1.svelte-1i8v7x1{font-family:var(--mono);font-size:.72rem;color:var(--text-muted)}@media (max-width: 680px){.counter-section.svelte-1i8v7x1.svelte-1i8v7x1{padding:2.5rem 1rem 1.5rem}.counter-sub.svelte-1i8v7x1.svelte-1i8v7x1{gap:1rem}.stats-strip.svelte-1i8v7x1.svelte-1i8v7x1{flex-direction:column}.strip-divider.svelte-1i8v7x1.svelte-1i8v7x1{width:auto;height:1px;margin:0 1rem}.top-bar.svelte-1i8v7x1.svelte-1i8v7x1{flex-wrap:wrap;gap:.6rem}.clock-block.svelte-1i8v7x1.svelte-1i8v7x1{margin-left:0}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.filter-bar.svelte-aa20kz.svelte-aa20kz{display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap}.model.svelte-aa20kz.svelte-aa20kz{font-size:.8rem;color:var(--text-primary)}.pagination.svelte-aa20kz.svelte-aa20kz{display:flex;align-items:center;justify-content:center;gap:1rem;margin-top:1.5rem}.pagination.svelte-aa20kz button.svelte-aa20kz{padding:.4rem .85rem;border:1px solid var(--border-subtle);background:var(--bg-raised);color:var(--text-secondary);border-radius:6px;cursor:pointer;font-size:.8rem;font-weight:500;transition:all .15s ease}.pagination.svelte-aa20kz button.svelte-aa20kz:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}.pagination.svelte-aa20kz button.svelte-aa20kz:disabled{opacity:.35;cursor:not-allowed}.page-info.svelte-aa20kz.svelte-aa20kz{font-size:.75rem;color:var(--text-muted)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.header-row.svelte-1iyktc5.svelte-1iyktc5{display:flex;align-items:center;margin-bottom:1.5rem}.page-title.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:1.1rem;font-weight:700;color:var(--text-primary)}.sections.svelte-1iyktc5.svelte-1iyktc5{display:flex;flex-direction:column;gap:1rem}.card.svelte-1iyktc5.svelte-1iyktc5{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:10px;padding:1.25rem;transition:border-color .2s}.card.svelte-1iyktc5.svelte-1iyktc5:hover{border-color:var(--border-medium)}.group-title.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:1rem}.fields.svelte-1iyktc5.svelte-1iyktc5{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem}.field.svelte-1iyktc5.svelte-1iyktc5{display:flex;flex-direction:column;gap:.25rem}.field.full.svelte-1iyktc5.svelte-1iyktc5{grid-column:1 / -1}.field-label.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-secondary)}.field-hint.svelte-1iyktc5.svelte-1iyktc5{font-size:.72rem;color:var(--text-muted);margin-top:-.1rem}.field-input.svelte-1iyktc5.svelte-1iyktc5{font-family:DM Sans,sans-serif;font-size:.85rem;padding:.45rem .65rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-primary);transition:border-color .15s,box-shadow .15s;width:100%}.field-input.svelte-1iyktc5.svelte-1iyktc5:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-dim)}.field-input.mono.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:.8rem}select.field-input.svelte-1iyktc5.svelte-1iyktc5{cursor:pointer}.section-error.svelte-1iyktc5.svelte-1iyktc5{margin-top:.75rem;font-size:.8rem;color:var(--rose)}.section-footer.svelte-1iyktc5.svelte-1iyktc5{display:flex;justify-content:flex-end;margin-top:1rem;padding-top:.75rem;border-top:1px solid var(--border-subtle)}.btn-save.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:.75rem;font-weight:600;padding:.45rem 1.1rem;border:1px solid var(--accent);border-radius:6px;background:var(--accent-dim);color:var(--accent);cursor:pointer;transition:all .15s;min-width:72px}.btn-save.svelte-1iyktc5.svelte-1iyktc5:hover:not(:disabled){background:var(--accent);color:#000}.btn-save.svelte-1iyktc5.svelte-1iyktc5:disabled{opacity:.55;cursor:not-allowed}.btn-save.saved.svelte-1iyktc5.svelte-1iyktc5{border-color:var(--green);background:var(--green-dim);color:var(--green)}.state-msg.svelte-1iyktc5.svelte-1iyktc5{color:var(--text-muted);padding:2rem;text-align:center}.state-msg.error.svelte-1iyktc5.svelte-1iyktc5{color:var(--rose)}.credential-row.svelte-1iyktc5.svelte-1iyktc5{display:flex;gap:.5rem;align-items:center}.credential-row.svelte-1iyktc5 .field-input.svelte-1iyktc5{flex:1}.btn-secondary.svelte-1iyktc5.svelte-1iyktc5{font-family:var(--mono);font-size:.75rem;font-weight:600;padding:.45rem .9rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);cursor:pointer;white-space:nowrap}.btn-secondary.svelte-1iyktc5.svelte-1iyktc5:disabled{opacity:.55;cursor:not-allowed}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{margin:0;padding:0;box-sizing:border-box}body{font-family:DM Sans,sans-serif;background:var(--bg-base);color:var(--text-primary);min-height:100vh;-webkit-font-smoothing:antialiased;transition:background .3s ease,color .3s ease}:root,:root[data-theme=dark]{--bg-base:#0b0e14;--bg-surface:#111620;--bg-raised:#171c28;--bg-hover:#1c2333;--border-subtle:rgba(255, 255, 255, .06);--border-medium:rgba(255, 255, 255, .1);--text-primary:#e6edf3;--text-secondary:#8b949e;--text-muted:#484f58;--accent:#f0b429;--accent-dim:rgba(240, 180, 41, .15);--accent-glow:rgba(240, 180, 41, .3);--green:#2ea66a;--green-dim:rgba(46, 166, 106, .15);--blue:#3b82f6;--blue-dim:rgba(59, 130, 246, .15);--purple:#a78bfa;--purple-dim:rgba(167, 139, 250, .15);--rose:#f43f5e;--rose-dim:rgba(244, 63, 94, .15);--mono:"JetBrains Mono", monospace;--grain-opacity:.03}:root[data-theme=light]{--bg-base:#f4f5f7;--bg-surface:#ffffff;--bg-raised:#f0f1f3;--bg-hover:#e8eaed;--border-subtle:rgba(0, 0, 0, .07);--border-medium:rgba(0, 0, 0, .12);--text-primary:#1a1d23;--text-secondary:#57606a;--text-muted:#8b949e;--accent:#c78c06;--accent-dim:rgba(199, 140, 6, .1);--accent-glow:rgba(199, 140, 6, .15);--green:#1a7f4b;--green-dim:rgba(26, 127, 75, .1);--blue:#2563eb;--blue-dim:rgba(37, 99, 235, .1);--purple:#7c3aed;--purple-dim:rgba(124, 58, 237, .1);--rose:#dc2626;--rose-dim:rgba(220, 38, 38, .1);--mono:"JetBrains Mono", monospace;--grain-opacity:.015}.grain.svelte-zqr7pm.svelte-zqr7pm{position:fixed;inset:0;pointer-events:none;z-index:9999;opacity:var(--grain-opacity);background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");background-repeat:repeat;background-size:128px}.app.svelte-zqr7pm.svelte-zqr7pm{display:flex;flex-direction:column;min-height:100vh}header.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:2rem;padding:0 2rem;height:56px;background:var(--bg-surface);border-bottom:1px solid var(--border-subtle);position:sticky;top:0;z-index:100;backdrop-filter:blur(12px);transition:background .3s ease,border-color .3s ease}.brand.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.5rem;flex-shrink:0;text-decoration:none}.logo.svelte-zqr7pm.svelte-zqr7pm{font-size:1.25rem;color:var(--accent);filter:drop-shadow(0 0 6px var(--accent-glow));transition:color .3s ease}.name.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-weight:700;font-size:.95rem;letter-spacing:-.02em;color:var(--text-primary);transition:color .3s ease}nav.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.25rem;flex:1}nav.svelte-zqr7pm a.svelte-zqr7pm{text-decoration:none;color:var(--text-secondary);padding:.4rem .75rem;border-radius:6px;font-size:.8rem;font-weight:500;line-height:1;transition:all .15s ease;white-space:nowrap}nav.svelte-zqr7pm a.svelte-zqr7pm:hover{color:var(--text-primary);background:var(--bg-hover)}nav.svelte-zqr7pm a.active.svelte-zqr7pm{color:var(--accent);background:var(--accent-dim)}.controls.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.35rem;padding:.35rem .6rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-size:.75rem;font-weight:500;cursor:pointer;transition:all .15s ease}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}.sync-toggle.svelte-zqr7pm.svelte-zqr7pm:disabled{opacity:.6;cursor:not-allowed}.sync-icon.svelte-zqr7pm.svelte-zqr7pm{font-size:.85rem;line-height:1}.sync-toggle.svelte-zqr7pm:disabled .sync-icon.svelte-zqr7pm{animation:svelte-zqr7pm-spin 1s linear infinite}@keyframes svelte-zqr7pm-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.sync-label.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-size:.7rem;font-weight:600;letter-spacing:.02em}.sync-label.ok.svelte-zqr7pm.svelte-zqr7pm{color:var(--green)}.sync-label.err.svelte-zqr7pm.svelte-zqr7pm{color:var(--rose)}.theme-toggle.svelte-zqr7pm.svelte-zqr7pm{display:flex;align-items:center;gap:.4rem;padding:.35rem .65rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-size:.75rem;font-weight:500;cursor:pointer;transition:all .15s ease}.theme-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}.theme-icon.svelte-zqr7pm.svelte-zqr7pm{font-size:.85rem;line-height:1}.theme-label.svelte-zqr7pm.svelte-zqr7pm{font-family:var(--mono);font-size:.7rem;font-weight:600;letter-spacing:.02em}.lang-toggle.svelte-zqr7pm.svelte-zqr7pm{padding:.35rem .75rem;border:1px solid var(--border-medium);border-radius:6px;background:var(--bg-raised);color:var(--text-secondary);font-family:var(--mono);font-size:.75rem;font-weight:600;cursor:pointer;transition:all .15s ease;letter-spacing:.02em}.lang-toggle.svelte-zqr7pm.svelte-zqr7pm:hover{border-color:var(--accent);color:var(--accent);box-shadow:0 0 12px var(--accent-dim)}main.svelte-zqr7pm.svelte-zqr7pm{flex:1;padding:2rem;max-width:1200px;width:100%;margin:0 auto;animation:svelte-zqr7pm-fadeUp .4s ease}@keyframes svelte-zqr7pm-fadeUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.card{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:10px;padding:1.25rem;transition:border-color .2s ease,background .3s ease}.card:hover{border-color:var(--border-medium)}.section-title{font-family:var(--mono);font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:.75rem}table{width:100%;border-collapse:collapse}th{font-family:var(--mono);font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);text-align:left;padding:.6rem .75rem;border-bottom:1px solid var(--border-subtle)}td{padding:.6rem .75rem;border-bottom:1px solid var(--border-subtle);font-size:.85rem;color:var(--text-secondary);transition:color .3s ease}tbody tr{transition:background .15s ease}tbody tr:hover{background:var(--bg-hover)}.mono{font-family:var(--mono)}.accent{color:var(--accent)}.green{color:var(--green)}.blue{color:var(--blue)}.purple{color:var(--purple)}.state-msg{text-align:center;padding:4rem 2rem;color:var(--text-muted);font-size:.9rem}.state-msg h2{font-family:var(--mono);font-size:1rem;font-weight:600;color:var(--text-secondary);margin-bottom:.5rem}.state-msg.error{color:var(--rose)}button{font-family:DM Sans,sans-serif}@media (max-width: 768px){header.svelte-zqr7pm.svelte-zqr7pm{flex-wrap:wrap;height:auto;padding:.75rem 1rem;gap:.5rem}nav.svelte-zqr7pm.svelte-zqr7pm{order:3;width:100%;overflow-x:auto;padding-bottom:.25rem}.controls.svelte-zqr7pm.svelte-zqr7pm{margin-left:auto}main.svelte-zqr7pm.svelte-zqr7pm{padding:1rem}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.filter-bar.svelte-aa20kz.svelte-aa20kz{display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap}.model.svelte-aa20kz.svelte-aa20kz{font-size:.8rem;color:var(--text-primary)}.pagination.svelte-aa20kz.svelte-aa20kz{display:flex;align-items:center;justify-content:center;gap:1rem;margin-top:1.5rem}.pagination.svelte-aa20kz button.svelte-aa20kz{padding:.4rem .85rem;border:1px solid var(--border-subtle);background:var(--bg-raised);color:var(--text-secondary);border-radius:6px;cursor:pointer;font-size:.8rem;font-weight:500;transition:all .15s ease}.pagination.svelte-aa20kz button.svelte-aa20kz:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}.pagination.svelte-aa20kz button.svelte-aa20kz:disabled{opacity:.35;cursor:not-allowed}.page-info.svelte-aa20kz.svelte-aa20kz{font-size:.75rem;color:var(--text-muted)}
|