@sunasteriskrnd/takumi 1.0.0-dev.45 → 1.0.0-dev.47
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/index.js +84 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19815,7 +19815,7 @@ var package_default;
|
|
|
19815
19815
|
var init_package = __esm(() => {
|
|
19816
19816
|
package_default = {
|
|
19817
19817
|
name: "@sunasteriskrnd/takumi",
|
|
19818
|
-
version: "1.0.0-dev.
|
|
19818
|
+
version: "1.0.0-dev.47",
|
|
19819
19819
|
description: "CLI tool for bootstrapping and managing Takumi projects",
|
|
19820
19820
|
type: "module",
|
|
19821
19821
|
repository: {
|
|
@@ -48344,7 +48344,12 @@ async function runPkceFlow(options2) {
|
|
|
48344
48344
|
codeChallenge: run.pair.challenge,
|
|
48345
48345
|
port: run.port
|
|
48346
48346
|
});
|
|
48347
|
-
|
|
48347
|
+
options2.onAuthUrl?.(url);
|
|
48348
|
+
try {
|
|
48349
|
+
await openBrowser(url);
|
|
48350
|
+
} catch (err) {
|
|
48351
|
+
options2.onOpenBrowserError?.(err instanceof Error ? err : new Error(String(err)));
|
|
48352
|
+
}
|
|
48348
48353
|
const callback = await Promise.race([received, timeoutPromise]);
|
|
48349
48354
|
const code = callback.searchParams.get("code");
|
|
48350
48355
|
const callbackState = callback.searchParams.get("state");
|
|
@@ -48364,7 +48369,9 @@ var init_pkce_flow = __esm(() => {
|
|
|
48364
48369
|
PkceTimeoutError = class PkceTimeoutError extends Error {
|
|
48365
48370
|
constructor() {
|
|
48366
48371
|
super(`Login timed out after 90s waiting for browser callback.
|
|
48367
|
-
` + " - Re-run `tkm auth login` if the browser opened but you didn't complete sign-in.\n" +
|
|
48372
|
+
` + " - Re-run `tkm auth login` if the browser opened but you didn't complete sign-in.\n" + ` - If the browser didn't open, copy the sign-in link printed above and open it
|
|
48373
|
+
` + ` manually in a browser on this machine.
|
|
48374
|
+
` + " - On a headless / WSL2 box without a browser, run `tkm auth login` from your\n" + " laptop and copy the token file to `<home>/.takumi/auth/token.json`.");
|
|
48368
48375
|
this.name = "PkceTimeoutError";
|
|
48369
48376
|
}
|
|
48370
48377
|
};
|
|
@@ -48397,7 +48404,7 @@ async function exchangeCodeForSession(webUrl, code, codeVerifier) {
|
|
|
48397
48404
|
}
|
|
48398
48405
|
return await res.json();
|
|
48399
48406
|
}
|
|
48400
|
-
async function runLoginFlow() {
|
|
48407
|
+
async function runLoginFlow(hooks = {}) {
|
|
48401
48408
|
const serverUrl = getServerUrl();
|
|
48402
48409
|
const pair = generatePkcePair();
|
|
48403
48410
|
const state = generateState();
|
|
@@ -48405,6 +48412,8 @@ async function runLoginFlow() {
|
|
|
48405
48412
|
const callback = await runPkceFlow({
|
|
48406
48413
|
state,
|
|
48407
48414
|
pair,
|
|
48415
|
+
onAuthUrl: hooks.onAuthUrl,
|
|
48416
|
+
onOpenBrowserError: hooks.onOpenBrowserError,
|
|
48408
48417
|
authUrl: ({ state: s, codeChallenge, port }) => `${serverUrl}/cli/auth?state=${encodeURIComponent(s)}` + `&code_challenge=${encodeURIComponent(codeChallenge)}` + `&port=${port}&prompt=1` + `&cli_version=${encodeURIComponent(cliVersion)}`
|
|
48409
48418
|
});
|
|
48410
48419
|
const tokens = await exchangeCodeForSession(serverUrl, callback.code, pair.verifier);
|
|
@@ -48439,15 +48448,29 @@ function reportLoginError(err) {
|
|
|
48439
48448
|
async function login() {
|
|
48440
48449
|
oe("Takumi login");
|
|
48441
48450
|
const spinner = de();
|
|
48442
|
-
|
|
48451
|
+
let spinning = false;
|
|
48443
48452
|
try {
|
|
48444
|
-
const result = await runLoginFlow(
|
|
48445
|
-
|
|
48453
|
+
const result = await runLoginFlow({
|
|
48454
|
+
onAuthUrl: (url) => {
|
|
48455
|
+
f2.step("Open this link to sign in (copy it if the browser doesn't open):");
|
|
48456
|
+
console.log(`
|
|
48457
|
+
${url}
|
|
48458
|
+
`);
|
|
48459
|
+
spinner.start("Waiting for sign-in in browser (90s timeout)…");
|
|
48460
|
+
spinning = true;
|
|
48461
|
+
},
|
|
48462
|
+
onOpenBrowserError: () => {
|
|
48463
|
+
spinner.message("Browser didn't open — copy the link above to sign in (90s timeout)…");
|
|
48464
|
+
}
|
|
48465
|
+
});
|
|
48466
|
+
if (spinning)
|
|
48467
|
+
spinner.stop("Signed in.");
|
|
48446
48468
|
if (result.email)
|
|
48447
48469
|
f2.success(`Signed in as ${result.email}`);
|
|
48448
48470
|
$e("You're ready to go.");
|
|
48449
48471
|
} catch (err) {
|
|
48450
|
-
|
|
48472
|
+
if (spinning)
|
|
48473
|
+
spinner.stop("Login failed.", 1);
|
|
48451
48474
|
reportLoginError(err);
|
|
48452
48475
|
process.exitCode = 1;
|
|
48453
48476
|
}
|
|
@@ -48631,7 +48654,18 @@ async function ensureAuthenticated(options2) {
|
|
|
48631
48654
|
if (!mod.runLoginFlow) {
|
|
48632
48655
|
throw new Error("Login command is not available in this build. Run `tkm auth login` manually.");
|
|
48633
48656
|
}
|
|
48634
|
-
await
|
|
48657
|
+
const { log: log2 } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
|
|
48658
|
+
await mod.runLoginFlow({
|
|
48659
|
+
onAuthUrl: (url) => {
|
|
48660
|
+
log2.step("Open this link to sign in (copy it if the browser doesn't open):");
|
|
48661
|
+
console.log(`
|
|
48662
|
+
${url}
|
|
48663
|
+
`);
|
|
48664
|
+
},
|
|
48665
|
+
onOpenBrowserError: () => {
|
|
48666
|
+
log2.warn("Browser didn't open — copy the link above to sign in.");
|
|
48667
|
+
}
|
|
48668
|
+
});
|
|
48635
48669
|
});
|
|
48636
48670
|
await runLogin();
|
|
48637
48671
|
const token = await getToken({ ...options2, forceConfigRefresh: false });
|
|
@@ -53557,6 +53591,44 @@ function tryOpenBrowser(target) {
|
|
|
53557
53591
|
init_logger();
|
|
53558
53592
|
import * as http from "node:http";
|
|
53559
53593
|
|
|
53594
|
+
// src/domains/sessions/analytics-daily-by-model.ts
|
|
53595
|
+
function buildDailyByModel(aggregates, oldestAllowedMs) {
|
|
53596
|
+
const byDayModel = new Map;
|
|
53597
|
+
for (const agg of aggregates) {
|
|
53598
|
+
const ms = startedMs(agg?.startedAt);
|
|
53599
|
+
if (ms === null)
|
|
53600
|
+
continue;
|
|
53601
|
+
const perModel = agg?.tokensByModel;
|
|
53602
|
+
if (!perModel || typeof perModel !== "object")
|
|
53603
|
+
continue;
|
|
53604
|
+
const date = dayKey(ms);
|
|
53605
|
+
if (Date.parse(`${date}T00:00:00.000Z`) < oldestAllowedMs)
|
|
53606
|
+
continue;
|
|
53607
|
+
let byModel = byDayModel.get(date);
|
|
53608
|
+
if (!byModel) {
|
|
53609
|
+
byModel = new Map;
|
|
53610
|
+
byDayModel.set(date, byModel);
|
|
53611
|
+
}
|
|
53612
|
+
for (const [model, mtok] of Object.entries(perModel)) {
|
|
53613
|
+
let acc = byModel.get(model);
|
|
53614
|
+
if (!acc) {
|
|
53615
|
+
acc = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
53616
|
+
byModel.set(model, acc);
|
|
53617
|
+
}
|
|
53618
|
+
accumulateTokens(acc, normalizeTokens(mtok));
|
|
53619
|
+
}
|
|
53620
|
+
}
|
|
53621
|
+
const rows = [];
|
|
53622
|
+
for (const [date, byModel] of byDayModel) {
|
|
53623
|
+
for (const [model, tokens] of byModel) {
|
|
53624
|
+
if (sumTokens(tokens) > 0)
|
|
53625
|
+
rows.push({ date, model, tokens });
|
|
53626
|
+
}
|
|
53627
|
+
}
|
|
53628
|
+
rows.sort((a3, b3) => a3.date.localeCompare(b3.date) || a3.model.localeCompare(b3.model));
|
|
53629
|
+
return rows;
|
|
53630
|
+
}
|
|
53631
|
+
|
|
53560
53632
|
// src/domains/sessions/analytics.ts
|
|
53561
53633
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
53562
53634
|
var PER_DAY_MAX = 371;
|
|
@@ -53670,6 +53742,7 @@ function foldAnalytics(aggregates, now, range) {
|
|
|
53670
53742
|
const rankedModels = [...tokensByModel.entries()].map(([label, tokens]) => ({ label, tokens, total: sumTokens(tokens) })).filter((m2) => m2.total > 0).sort((a3, b3) => b3.total - a3.total || a3.label.localeCompare(b3.label)).slice(0, TOP_PROJECTS);
|
|
53671
53743
|
const byModel = rankedModels.map(({ label, total }) => ({ label, tokens: total }));
|
|
53672
53744
|
const byModelDetailed = rankedModels.map(({ label, tokens }) => ({ label, tokens }));
|
|
53745
|
+
const dailyByModel = buildDailyByModel(aggregates, oldestAllowedMs);
|
|
53673
53746
|
const cacheDenom = totals.cacheRead + totals.input;
|
|
53674
53747
|
const cacheHitRate = cacheDenom > 0 ? totals.cacheRead / cacheDenom : 0;
|
|
53675
53748
|
return {
|
|
@@ -53691,7 +53764,8 @@ function foldAnalytics(aggregates, now, range) {
|
|
|
53691
53764
|
byProject,
|
|
53692
53765
|
daily,
|
|
53693
53766
|
byModel,
|
|
53694
|
-
byModelDetailed
|
|
53767
|
+
byModelDetailed,
|
|
53768
|
+
dailyByModel
|
|
53695
53769
|
},
|
|
53696
53770
|
window: {
|
|
53697
53771
|
earliest: earliestMs === null ? null : new Date(earliestMs).toISOString(),
|