tokalytics 2.0.0

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/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Tokalytics
2
+
3
+ Ferramenta **local** (Go) que agrega uso de tokens e quotas: **menu bar** (system tray) + **dashboard web** para Claude Code, Cursor, Gemini CLI e dados em nuvem (Claude), quando configurado.
4
+
5
+ Os dados permanecem na sua máquina; nada é enviado para servidores externos pelo app.
6
+
7
+ ## Requisitos
8
+
9
+ - [Go](https://go.dev/dl/) 1.21+ (para build / `go run`)
10
+ - Node/npm opcional — apenas atalhos em `package.json` para os mesmos comandos Go
11
+
12
+ ## Como executar
13
+
14
+ ### Desenvolvimento (sem gerar binário)
15
+
16
+ ```bash
17
+ go run main.go
18
+ ```
19
+
20
+ ### Build em Go (binário `tokalytics`)
21
+
22
+ Na raiz do repositório:
23
+
24
+ ```bash
25
+ go build -o tokalytics main.go
26
+ ```
27
+
28
+ Isso gera o executável `tokalytics` no diretório atual. Para rodar o app após o build:
29
+
30
+ ```bash
31
+ ./tokalytics
32
+ ```
33
+
34
+ ### Atalhos npm (equivalentes)
35
+
36
+ ```bash
37
+ npm run dev # go run main.go
38
+ npm run build # go build -o tokalytics main.go
39
+ npm run start # compila e em seguida executa ./tokalytics
40
+ ```
41
+
42
+ Na primeira execução o app sobe o **servidor HTTP na porta `3456`** e o ícone na barra de menus. Use **«Abrir Dashboard»** no menu ou acesse [http://127.0.0.1:3456](http://127.0.0.1:3456).
43
+
44
+ ## Dashboard
45
+
46
+ Interface web em abas:
47
+
48
+ | Aba | Conteúdo |
49
+ |-----|----------|
50
+ | **Visão geral** | Hero, quotas (local / provedores), explicação de tokens, totais |
51
+ | **Gráficos** | Gráfico diário de tokens, distribuição por modelo |
52
+ | **Insights** | Recomendações automáticas com base no período |
53
+ | **Prompts** | Mensagens que mais consumiram tokens |
54
+ | **Sessões** | Lista pesquisável; clique em uma sessão para ver o detalhe (turns, custo por turno) |
55
+
56
+ Há atalhos para **atualizar dados**, **compartilhar stats** (PNG) e **configurações** (cookies opcionais para APIs em nuvem).
57
+
58
+ ## Licença
59
+
60
+ MIT
61
+
62
+ ## Créditos
63
+
64
+ Baseado em ideias de ferramentas como **claude-spend** e **CodexBar**, evoluído como Tokalytics.
package/bin/run.js ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('path');
5
+ const { spawnSync } = require('child_process');
6
+ const fs = require('fs');
7
+
8
+ const BIN_PATH = path.join(__dirname, process.platform === 'win32' ? 'tokalytics.exe' : 'tokalytics');
9
+
10
+ if (!fs.existsSync(BIN_PATH)) {
11
+ console.error('Tokalytics: binário não encontrado. Tente reinstalar: npm install -g tokalytics');
12
+ process.exit(1);
13
+ }
14
+
15
+ const result = spawnSync(BIN_PATH, process.argv.slice(2), { stdio: 'inherit' });
16
+
17
+ if (result.error) {
18
+ console.error('Erro ao executar tokalytics:', result.error.message);
19
+ process.exit(1);
20
+ }
21
+
22
+ process.exit(result.status ?? 0);
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "tokalytics",
3
+ "version": "2.0.0",
4
+ "description": "Veja para onde vão seus tokens do Claude Code, Gemini CLI, Cursor e Codex. Reescrito em Go como Tokalytics.",
5
+ "bin": {
6
+ "tokalytics": "bin/run.js"
7
+ },
8
+ "files": [
9
+ "bin/run.js",
10
+ "scripts/postinstall.js"
11
+ ],
12
+ "scripts": {
13
+ "postinstall": "node scripts/postinstall.js",
14
+ "start": "go build -o tokalytics main.go && ./tokalytics",
15
+ "dev": "go run main.go",
16
+ "build": "go build -o tokalytics main.go"
17
+ },
18
+ "keywords": [
19
+ "claude",
20
+ "claude-code",
21
+ "tokens",
22
+ "usage",
23
+ "analytics",
24
+ "dashboard",
25
+ "spend",
26
+ "codexbar",
27
+ "golang",
28
+ "tokalytics"
29
+ ],
30
+ "author": "Aniket Parihar & Kaic Murilo",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/kaicmurilo/tokalytics.git"
35
+ }
36
+ }
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const https = require('https');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { execSync } = require('child_process');
8
+
9
+ const REPO = 'kaicmurilo/tokalytics';
10
+ const BIN_DIR = path.join(__dirname, '..', 'bin');
11
+ const BIN_PATH = path.join(BIN_DIR, process.platform === 'win32' ? 'tokalytics.exe' : 'tokalytics');
12
+
13
+ function getPlatformBinary() {
14
+ const platform = process.platform;
15
+ const arch = process.arch;
16
+
17
+ const platformMap = {
18
+ 'darwin-arm64': 'tokalytics-darwin-arm64',
19
+ 'darwin-x64': 'tokalytics-darwin-amd64',
20
+ 'linux-arm64': 'tokalytics-linux-arm64',
21
+ 'linux-x64': 'tokalytics-linux-amd64',
22
+ 'win32-x64': 'tokalytics-windows-amd64.exe',
23
+ };
24
+
25
+ const key = `${platform}-${arch}`;
26
+ const name = platformMap[key];
27
+ if (!name) {
28
+ throw new Error(`Plataforma não suportada: ${key}`);
29
+ }
30
+ return name;
31
+ }
32
+
33
+ function fetchJson(url) {
34
+ return new Promise((resolve, reject) => {
35
+ const options = { headers: { 'User-Agent': 'tokalytics-installer' } };
36
+ https.get(url, options, (res) => {
37
+ if (res.statusCode === 302 || res.statusCode === 301) {
38
+ return fetchJson(res.headers.location).then(resolve).catch(reject);
39
+ }
40
+ let data = '';
41
+ res.on('data', (chunk) => (data += chunk));
42
+ res.on('end', () => {
43
+ try { resolve(JSON.parse(data)); }
44
+ catch (e) { reject(new Error('Resposta inválida da API do GitHub')); }
45
+ });
46
+ }).on('error', reject);
47
+ });
48
+ }
49
+
50
+ function downloadFile(url, dest) {
51
+ return new Promise((resolve, reject) => {
52
+ const options = { headers: { 'User-Agent': 'tokalytics-installer' } };
53
+ const file = fs.createWriteStream(dest);
54
+ const follow = (u) => {
55
+ https.get(u, options, (res) => {
56
+ if (res.statusCode === 302 || res.statusCode === 301) {
57
+ return follow(res.headers.location);
58
+ }
59
+ if (res.statusCode !== 200) {
60
+ return reject(new Error(`Download falhou: HTTP ${res.statusCode}`));
61
+ }
62
+ res.pipe(file);
63
+ file.on('finish', () => file.close(resolve));
64
+ }).on('error', (err) => {
65
+ fs.unlink(dest, () => {});
66
+ reject(err);
67
+ });
68
+ };
69
+ follow(url);
70
+ });
71
+ }
72
+
73
+ async function install() {
74
+ console.log('Tokalytics: buscando última versão...');
75
+
76
+ const release = await fetchJson(`https://api.github.com/repos/${REPO}/releases/latest`);
77
+ const version = release.tag_name;
78
+ const binaryName = getPlatformBinary();
79
+
80
+ const asset = release.assets.find((a) => a.name === binaryName);
81
+ if (!asset) {
82
+ throw new Error(`Binário "${binaryName}" não encontrado na release ${version}`);
83
+ }
84
+
85
+ console.log(`Tokalytics: baixando ${binaryName} (${version})...`);
86
+ if (!fs.existsSync(BIN_DIR)) fs.mkdirSync(BIN_DIR, { recursive: true });
87
+
88
+ await downloadFile(asset.browser_download_url, BIN_PATH);
89
+ fs.chmodSync(BIN_PATH, 0o755);
90
+
91
+ console.log(`Tokalytics ${version} instalado com sucesso!`);
92
+ console.log('Execute: tokalytics');
93
+ }
94
+
95
+ install().catch((err) => {
96
+ console.error('Erro na instalação do Tokalytics:', err.message);
97
+ process.exit(1);
98
+ });