token-rats 0.0.1 → 0.0.3

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 (3) hide show
  1. package/README.md +0 -4
  2. package/dist/index.js +86 -23
  3. package/package.json +32 -10
package/README.md CHANGED
@@ -86,7 +86,3 @@ Authentication uses a device-code flow:
86
86
  Token Rats is open source. The CLI source is in [`packages/cli/`](.) and the parsers are in [`packages/parsers/`](../parsers/). You can inspect exactly what is read from your disk and what is sent to the server.
87
87
 
88
88
  **Privacy posture:** Token Rats reads usage counts only — never prompts or completions. The parser source is in `packages/parsers/`. We literally can't read what you typed.
89
-
90
- ## License
91
-
92
- MIT
package/dist/index.js CHANGED
@@ -1,5 +1,37 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/commands/install-cursor.ts
4
+ import { spawn } from "node:child_process";
5
+ async function installCursorCommand(opts = {}) {
6
+ const pm = opts.packageManager ?? "npm";
7
+ console.log("\x1B[1mtoken-rats install-cursor\x1B[0m");
8
+ console.log(
9
+ "Installs better-sqlite3 globally for faster Cursor extraction.\nYou don't need this for Cursor support to work \u2014 sql.js (already\nbundled) handles it. This is purely a speed upgrade for large DBs.\n"
10
+ );
11
+ const args = ["install", "-g", "better-sqlite3@^9.4.3"];
12
+ console.log(`\x1B[2m$ ${pm} ${args.join(" ")}\x1B[0m
13
+ `);
14
+ const exitCode = await new Promise((resolve) => {
15
+ const child = spawn(pm, args, { stdio: "inherit" });
16
+ child.on("close", (code) => resolve(code ?? 1));
17
+ child.on("error", (err) => {
18
+ console.error(`\x1B[31mFailed to launch ${pm}: ${err.message}\x1B[0m`);
19
+ resolve(1);
20
+ });
21
+ });
22
+ if (exitCode === 0) {
23
+ console.log(
24
+ "\n\x1B[32m\u2713\x1B[0m Done. Future `token-rats sync` runs will prefer better-sqlite3."
25
+ );
26
+ return;
27
+ }
28
+ console.error(
29
+ `
30
+ \x1B[31mInstall failed (exit ${exitCode}). Cursor still works via sql.js \u2014 no action required.\x1B[0m`
31
+ );
32
+ process.exit(exitCode);
33
+ }
34
+
3
35
  // ../../node_modules/.pnpm/zod@3.23.8/node_modules/zod/lib/index.mjs
4
36
  var util;
5
37
  (function(util2) {
@@ -4223,8 +4255,6 @@ var ENDPOINTS = {
4223
4255
  authCliPoll: "/v1/auth/cli/poll",
4224
4256
  // Phase 2 Track G+H
4225
4257
  meRooms: "/v1/me/rooms",
4226
- // Referral tracking
4227
- meReferrals: "/v1/me/referrals",
4228
4258
  leaveRoom: (code) => `/v1/rooms/${code}/leave`,
4229
4259
  renameRoom: (code) => `/v1/rooms/${code}`,
4230
4260
  roomActivity: (code) => `/v1/rooms/${code}/activity`,
@@ -4307,19 +4337,6 @@ var LiveEvent = z.discriminatedUnion("kind", [
4307
4337
  })
4308
4338
  ]);
4309
4339
 
4310
- // ../contracts/src/referrals.ts
4311
- var Referral = z.object({
4312
- handle: z.string(),
4313
- avatarUrl: z.string().url().nullable(),
4314
- /** Unix ms when the referee created their account. */
4315
- joinedAt: z.number().int().positive()
4316
- });
4317
- var GetReferralsResponse = z.object({
4318
- count: z.number().int().nonnegative(),
4319
- /** Most-recent first, up to 20. */
4320
- recent: z.array(Referral)
4321
- });
4322
-
4323
4340
  // src/lib/api.ts
4324
4341
  var DEFAULT_API_URL = "https://api.tokenrats.com";
4325
4342
  function isTransient(status) {
@@ -4986,6 +5003,7 @@ function toNonNegInt3(v) {
4986
5003
  }
4987
5004
 
4988
5005
  // src/lib/cursor-extract.ts
5006
+ import { readFile } from "node:fs/promises";
4989
5007
  async function tryNodeSqlite(dbPath) {
4990
5008
  let DatabaseConstructor;
4991
5009
  try {
@@ -4997,6 +5015,42 @@ async function tryNodeSqlite(dbPath) {
4997
5015
  }
4998
5016
  return readWithDb(() => new DatabaseConstructor(dbPath, { readOnly: true }));
4999
5017
  }
5018
+ async function trySqlJs(dbPath) {
5019
+ let initSqlJs;
5020
+ try {
5021
+ const mod = await import("sql.js");
5022
+ initSqlJs = mod.default ?? mod;
5023
+ } catch {
5024
+ return null;
5025
+ }
5026
+ let SQL;
5027
+ let fileBytes;
5028
+ try {
5029
+ SQL = await initSqlJs();
5030
+ fileBytes = await readFile(dbPath);
5031
+ } catch {
5032
+ return null;
5033
+ }
5034
+ const sqlDb = new SQL.Database(new Uint8Array(fileBytes));
5035
+ const adapter = {
5036
+ prepare: (sql) => ({
5037
+ all: () => {
5038
+ const results = sqlDb.exec(sql);
5039
+ if (results.length === 0) return [];
5040
+ const { columns, values } = results[0];
5041
+ return values.map((row) => {
5042
+ const obj = {};
5043
+ for (let i = 0; i < columns.length; i++) {
5044
+ obj[columns[i]] = row[i];
5045
+ }
5046
+ return obj;
5047
+ });
5048
+ }
5049
+ }),
5050
+ close: () => sqlDb.close()
5051
+ };
5052
+ return readWithDb(() => adapter);
5053
+ }
5000
5054
  async function tryBetterSqlite3(dbPath) {
5001
5055
  let Database;
5002
5056
  try {
@@ -5087,13 +5141,17 @@ async function readCursorDb(dbPath) {
5087
5141
  if (fromNodeSqlite !== null) {
5088
5142
  return { rows: fromNodeSqlite, skipped: null };
5089
5143
  }
5144
+ const fromSqlJs = await trySqlJs(dbPath);
5145
+ if (fromSqlJs !== null) {
5146
+ return { rows: fromSqlJs, skipped: null };
5147
+ }
5090
5148
  const fromBetter = await tryBetterSqlite3(dbPath);
5091
5149
  if (fromBetter !== null) {
5092
5150
  return { rows: fromBetter, skipped: null };
5093
5151
  }
5094
5152
  return {
5095
5153
  rows: [],
5096
- skipped: "Could not open Cursor DB (no sqlite driver available). Skipping Cursor source."
5154
+ skipped: "Could not open Cursor DB (sqlite drivers unavailable). Run `npx token-rats install-cursor` for native speed, or upgrade to Node \u226522.5."
5097
5155
  };
5098
5156
  }
5099
5157
 
@@ -5565,7 +5623,7 @@ async function whoamiCommand(opts) {
5565
5623
 
5566
5624
  // src/index.ts
5567
5625
  function getVersion() {
5568
- return "0.0.1";
5626
+ return "0.0.3";
5569
5627
  }
5570
5628
  function printHelp() {
5571
5629
  console.log(`
@@ -5575,12 +5633,14 @@ function printHelp() {
5575
5633
  token-rats <command> [flags]
5576
5634
 
5577
5635
  \x1B[1mCommands:\x1B[0m
5578
- login Authenticate with Token Rats (opens browser)
5579
- sync Read local Claude Code + Cursor logs and upload counts
5580
- watch Watch logs in real-time; upload new sessions as they appear
5581
- whoami Show the currently signed-in account
5582
- logout Clear your stored credentials
5583
- help Show this help message
5636
+ login Authenticate with Token Rats (opens browser)
5637
+ sync Read local Claude Code + Cursor logs and upload counts
5638
+ watch Watch logs in real-time; upload new sessions as they appear
5639
+ whoami Show the currently signed-in account
5640
+ logout Clear your stored credentials
5641
+ install-cursor Install better-sqlite3 globally for faster Cursor reads
5642
+ (sql.js works out of the box \u2014 this is opt-in speed-up)
5643
+ help Show this help message
5584
5644
 
5585
5645
  \x1B[1mFlags (all commands):\x1B[0m
5586
5646
  --api-url <url> Override API URL (default: https://api.tokenrats.com)
@@ -5664,6 +5724,9 @@ async function main() {
5664
5724
  case "logout":
5665
5725
  logoutCommand();
5666
5726
  break;
5727
+ case "install-cursor":
5728
+ await installCursorCommand();
5729
+ break;
5667
5730
  default:
5668
5731
  console.error(`\x1B[31mUnknown command: ${command}\x1B[0m`);
5669
5732
  console.error(`Run \x1B[1mtoken-rats help\x1B[0m for a list of commands.`);
package/package.json CHANGED
@@ -1,36 +1,58 @@
1
1
  {
2
2
  "name": "token-rats",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Sync your Claude Code + Cursor token usage to your Token Rats leaderboard.",
5
- "license": "MIT",
5
+ "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "token-rats": "./dist/index.js"
9
9
  },
10
- "files": ["dist", "README.md"],
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/hsalberti/token-rats.git",
17
+ "directory": "packages/cli"
18
+ },
19
+ "homepage": "https://tokenrats.com",
20
+ "keywords": [
21
+ "claude",
22
+ "claude-code",
23
+ "cursor",
24
+ "tokens",
25
+ "leaderboard",
26
+ "ai-usage"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
11
31
  "scripts": {
12
32
  "build": "tsc --noEmit -p tsconfig.json && node build.mjs",
13
33
  "typecheck": "tsc --noEmit",
14
34
  "dev": "tsx src/index.ts",
15
- "test": "vitest run"
16
- },
17
- "dependencies": {
18
- "@token-rats/contracts": "workspace:*",
19
- "@token-rats/parsers": "workspace:*",
20
- "@token-rats/pricing": "workspace:*"
35
+ "test": "vitest run",
36
+ "prepublishOnly": "node build.mjs"
21
37
  },
22
38
  "optionalDependencies": {
23
- "better-sqlite3": "^9.4.3",
24
39
  "chokidar": "^3.6.0",
25
40
  "clipboardy": "^4.0.0",
26
41
  "open": "^10.1.0"
27
42
  },
28
43
  "devDependencies": {
44
+ "@token-rats/contracts": "workspace:*",
45
+ "@token-rats/parsers": "workspace:*",
46
+ "@token-rats/pricing": "workspace:*",
29
47
  "@types/better-sqlite3": "^7.6.12",
30
48
  "@types/node": "22.10.2",
49
+ "@types/sql.js": "^1.4.11",
31
50
  "esbuild": "^0.24.2",
32
51
  "tsx": "4.19.2",
33
52
  "typescript": "5.7.2",
34
53
  "vitest": "2.1.8"
54
+ },
55
+ "dependencies": {
56
+ "sql.js": "^1.14.1"
35
57
  }
36
58
  }