@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.
Files changed (2) hide show
  1. package/dist/index.js +84 -10
  2. 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.45",
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
- await openBrowser(url);
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" + " - 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`.");
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
- spinner.start("Opening browser for sign-in (90s timeout)…");
48451
+ let spinning = false;
48443
48452
  try {
48444
- const result = await runLoginFlow();
48445
- spinner.stop("Signed in.");
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
- spinner.stop("Login failed.", 1);
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 mod.runLoginFlow();
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(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunasteriskrnd/takumi",
3
- "version": "1.0.0-dev.45",
3
+ "version": "1.0.0-dev.47",
4
4
  "description": "CLI tool for bootstrapping and managing Takumi projects",
5
5
  "type": "module",
6
6
  "repository": {