codebrag
Version:
CLI tool for tracking Claude Code usage and leaderboard participation
156 lines (131 loc) • 4.04 kB
JavaScript
import { readFile, writeFile, mkdir, unlink } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';
import { existsSync } from 'fs';
import { API_BASE_URL } from './constants.js';
const CLAUDE_DIR = join(homedir(), '.claude');
const CONFIG_FILE = join(CLAUDE_DIR, 'leaderboard.json');
const HOOK_SCRIPT_PATH = join(CLAUDE_DIR, 'count_tokens.js');
const SETTINGS_JSON_PATH = join(CLAUDE_DIR, 'settings.json');
export async function ensureConfigDir() {
if (!existsSync(CLAUDE_DIR)) {
await mkdir(CLAUDE_DIR, { recursive: true });
}
}
export async function loadConfig() {
try {
const content = await readFile(CONFIG_FILE, 'utf-8');
return JSON.parse(content);
} catch (error) {
// maybe we should throw an error here instead??
return {
twitterUrl: "@your_handle",
endpoint: API_BASE_URL
};
}
}
export async function saveConfig(config) {
await ensureConfigDir();
await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
}
export async function checkAuthStatus() {
try {
const config = await loadConfig();
// Check for OAuth 1.0a authentication
const isAuthenticated =
config.twitterUserId &&
config.oauth_token &&
config.oauth_token_secret &&
config.twitterUrl !== "@your_handle";
return {
isAuthenticated,
twitterHandle: config.twitterUrl || "@your_handle",
twitterUserId: config.twitterUserId,
lastAuthenticated: config.lastAuthenticated,
oauthVersion: '1.0a'
};
} catch (error) {
return {
isAuthenticated: false,
twitterHandle: "@your_handle",
twitterUserId: null,
lastAuthenticated: null,
oauthVersion: null
};
}
}
export async function clearAuthData() {
const config = await loadConfig();
// Remove OAuth 1.0a fields
delete config.oauth_token;
delete config.oauth_token_secret;
// Remove common fields
delete config.twitterUserId;
delete config.lastAuthenticated;
delete config.oauthVersion;
// Reset to placeholder
config.twitterUrl = "@your_handle";
await saveConfig(config);
}
async function removeHookFromJson() {
if (!existsSync(SETTINGS_JSON_PATH)) {
return false;
}
try {
const content = await readFile(SETTINGS_JSON_PATH, 'utf-8');
const settings = JSON.parse(content);
if (!settings.hooks?.Stop || !Array.isArray(settings.hooks.Stop)) {
return false;
}
// Remove our hook entry
const initialLength = settings.hooks.Stop.length;
settings.hooks.Stop = settings.hooks.Stop.filter(stopHook =>
!stopHook.hooks?.some(hook =>
hook.type === 'command' && hook.command === HOOK_SCRIPT_PATH
)
);
if (settings.hooks.Stop.length < initialLength) {
// Clean up empty structures
if (settings.hooks.Stop.length === 0) {
delete settings.hooks.Stop;
if (Object.keys(settings.hooks).length === 0) {
delete settings.hooks;
}
}
// Write back the updated settings
await writeFile(SETTINGS_JSON_PATH, JSON.stringify(settings, null, 2), 'utf-8');
return true;
}
} catch (error) {
console.error('Error removing hook from JSON:', error);
}
return false;
}
export async function removeAllCodebragFiles() {
const results = {
leaderboardConfig: false,
hookScript: false,
settingsJson: false
};
// Remove leaderboard.json
if (existsSync(CONFIG_FILE)) {
try {
await unlink(CONFIG_FILE);
results.leaderboardConfig = true;
} catch (error) {
console.error('Error removing leaderboard.json:', error);
}
}
// Remove count_tokens.js
if (existsSync(HOOK_SCRIPT_PATH)) {
try {
await unlink(HOOK_SCRIPT_PATH);
results.hookScript = true;
} catch (error) {
console.error('Error removing count_tokens.js:', error);
}
}
// Remove hook from settings.json
results.settingsJson = await removeHookFromJson();
return results;
}